diff --git a/build.gradle.kts b/build.gradle.kts index 1b2eb5614b9..38ff7b04393 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -155,7 +155,7 @@ subprojects { } } - if (!this.name.contains("sample") && !this.name.contains("integration-tests") && this.name != "sentry-test-support" && this.name != "sentry-compose-helper") { + if (!this.name.contains("sample") && !this.name.contains("integration-tests") && this.name != "sentry-system-test-support" && this.name != "sentry-test-support" && this.name != "sentry-compose-helper") { apply() apply() diff --git a/buildSrc/src/main/java/Config.kt b/buildSrc/src/main/java/Config.kt index 03b6849a6ba..b0e56eb2dc4 100644 --- a/buildSrc/src/main/java/Config.kt +++ b/buildSrc/src/main/java/Config.kt @@ -75,6 +75,7 @@ object Config { val log4j2Core = "org.apache.logging.log4j:log4j-core:$log4j2Version" val jacksonDatabind = "com.fasterxml.jackson.core:jackson-databind" + val jacksonKotlin = "com.fasterxml.jackson.module:jackson-module-kotlin:2.18.3" val springBootStarter = "org.springframework.boot:spring-boot-starter:$springBootVersion" val springBootStarterGraphql = "org.springframework.boot:spring-boot-starter-graphql:$springBootVersion" diff --git a/codecov.yml b/codecov.yml index 7dd03ca5e85..66a0719b606 100644 --- a/codecov.yml +++ b/codecov.yml @@ -16,5 +16,6 @@ coverage: ignore: - "**/src/test/*" - "sentry-android-integration-tests/*" + - "sentry-system-test-support/*" - "sentry-test-support/*" - "sentry-samples/*" 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 bd08b78c048..1f31fbfc05f 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 @@ -6,7 +6,6 @@ plugins { id(Config.BuildPlugins.springDependencyManagement) version Config.BuildPlugins.springDependencyManagementVersion kotlin("jvm") kotlin("plugin.spring") version Config.kotlinVersion - id("com.apollographql.apollo3") version "3.8.2" } group = "io.sentry.sample.spring-boot-jakarta" @@ -57,6 +56,7 @@ dependencies { // database query tracing implementation(projects.sentryJdbc) runtimeOnly(Config.TestLibs.hsqldb) + testImplementation(projects.sentrySystemTestSupport) testImplementation(Config.Libs.springBoot3StarterTest) { exclude(group = "org.junit.vintage", module = "junit-vintage-engine") } @@ -103,13 +103,3 @@ tasks.named("test").configure { excludeTestsMatching("io.sentry.systemtest.*") } } - -apollo { - service("service") { - srcDir("src/test/graphql") - packageName.set("io.sentry.samples.graphql") - outputDirConnection { - connectToKotlinSourceSet("test") - } - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/DistributedTracingSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/DistributedTracingSystemTest.kt index 3b4accef82a..aa707f8b6e4 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/DistributedTracingSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/DistributedTracingSystemTest.kt @@ -1,10 +1,8 @@ package io.sentry.systemtest import io.sentry.protocol.SentryId -import io.sentry.samples.spring.boot.jakarta.Person import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotEquals @@ -25,10 +23,12 @@ class DistributedTracingSystemTest { val restClient = testHelper.restClient restClient.getPersonDistributedTracing( 1L, - "$traceId-424cffc8f94feeee-1", - "sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rand=0.456789,sentry-sample_rate=0.5,sentry-sampled=true,sentry-trace_id=$traceId,sentry-transaction=HTTP%20GET" + mapOf( + "sentry-trace" to "$traceId-424cffc8f94feeee-1", + "baggage" to "sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rand=0.456789,sentry-sample_rate=0.5,sentry-sampled=true,sentry-trace_id=$traceId,sentry-transaction=HTTP%20GET" + ) ) - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, restClient.lastKnownStatusCode) + assertEquals(500, restClient.lastKnownStatusCode) testHelper.ensureTransactionReceived { transaction, envelopeHeader -> transaction.transaction == "GET /tracing/{id}" && @@ -47,10 +47,12 @@ class DistributedTracingSystemTest { val restClient = testHelper.restClient restClient.getPersonDistributedTracing( 1L, - "$traceId-424cffc8f94feeee-0", - "sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rand=0.456789,sentry-sample_rate=0.5,sentry-sampled=false,sentry-trace_id=$traceId,sentry-transaction=HTTP%20GET" + mapOf( + "sentry-trace" to "$traceId-424cffc8f94feeee-0", + "baggage" to "sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rand=0.456789,sentry-sample_rate=0.5,sentry-sampled=false,sentry-trace_id=$traceId,sentry-transaction=HTTP%20GET" + ) ) - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, restClient.lastKnownStatusCode) + assertEquals(500, restClient.lastKnownStatusCode) testHelper.ensureNoTransactionReceived { transaction, envelopeHeader -> transaction.transaction == "GET /tracing/{id}" @@ -67,10 +69,12 @@ class DistributedTracingSystemTest { val restClient = testHelper.restClient restClient.getPersonDistributedTracing( 1L, - "$traceId-424cffc8f94feeee-1", - "sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rate=0.5,sentry-sampled=true,sentry-trace_id=$traceId,sentry-transaction=HTTP%20GET" + mapOf( + "sentry-trace" to "$traceId-424cffc8f94feeee-1", + "baggage" to "sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rate=0.5,sentry-sampled=true,sentry-trace_id=$traceId,sentry-transaction=HTTP%20GET" + ) ) - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, restClient.lastKnownStatusCode) + assertEquals(500, restClient.lastKnownStatusCode) var sampleRand1: String? = null var sampleRand2: String? = null @@ -113,10 +117,12 @@ class DistributedTracingSystemTest { val restClient = testHelper.restClient restClient.getPersonDistributedTracing( 1L, - "$traceId-424cffc8f94feeee", - "sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rate=0.5,sentry-trace_id=$traceId,sentry-transaction=HTTP%20GET" + mapOf( + "sentry-trace" to "$traceId-424cffc8f94feeee", + "baggage" to "sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rate=0.5,sentry-trace_id=$traceId,sentry-transaction=HTTP%20GET" + ) ) - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, restClient.lastKnownStatusCode) + assertEquals(500, restClient.lastKnownStatusCode) var sampleRate1: String? = null var sampleRate2: String? = null @@ -161,10 +167,12 @@ class DistributedTracingSystemTest { val person = Person("firstA", "lastB") val returnedPerson = restClient.createPersonDistributedTracing( person, - "$traceId-424cffc8f94feeee-1", - "sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rand=0.456789,sentry-sample_rate=0.5,sentry-sampled=true,sentry-trace_id=$traceId,sentry-transaction=HTTP%20GET" + mapOf( + "sentry-trace" to "$traceId-424cffc8f94feeee-1", + "baggage" to "sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rand=0.456789,sentry-sample_rate=0.5,sentry-sampled=true,sentry-trace_id=$traceId,sentry-transaction=HTTP%20GET" + ) ) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) assertEquals(person.firstName, returnedPerson!!.firstName) assertEquals(person.lastName, returnedPerson!!.lastName) diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt index 3eed9c69cad..4f7661dc4b3 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt @@ -1,9 +1,7 @@ package io.sentry.systemtest -import io.sentry.samples.spring.boot.jakarta.Person import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals @@ -21,7 +19,7 @@ class PersonSystemTest { fun `get person fails`() { val restClient = testHelper.restClient restClient.getPerson(1L) - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, restClient.lastKnownStatusCode) + assertEquals(500, restClient.lastKnownStatusCode) testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughOtelApi") && @@ -34,7 +32,7 @@ class PersonSystemTest { val restClient = testHelper.restClient val person = Person("firstA", "lastB") val returnedPerson = restClient.createPerson(person) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) assertEquals(person.firstName, returnedPerson!!.firstName) assertEquals(person.lastName, returnedPerson!!.lastName) diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt index a32735e7e6b..80b9bd4f310 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt @@ -2,7 +2,6 @@ package io.sentry.systemtest import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals @@ -20,7 +19,7 @@ class TodoSystemTest { fun `get todo works`() { val restClient = testHelper.restClient restClient.getTodo(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "todoSpanOtelApi") && @@ -33,7 +32,7 @@ class TodoSystemTest { fun `get todo webclient works`() { val restClient = testHelper.restClient restClient.getTodoWebclient(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "http.client") @@ -44,7 +43,7 @@ class TodoSystemTest { fun `get todo restclient works`() { val restClient = testHelper.restClient restClient.getTodoRestClient(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "todoRestClientSpanOtelApi") && 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 acfc0d24d9e..dce546c8c4e 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 @@ -7,7 +7,6 @@ plugins { id(Config.BuildPlugins.springDependencyManagement) version Config.BuildPlugins.springDependencyManagementVersion kotlin("jvm") kotlin("plugin.spring") version Config.kotlinVersion - id("com.apollographql.apollo3") version "3.8.2" } group = "io.sentry.sample.spring-boot-jakarta" @@ -58,6 +57,8 @@ dependencies { // database query tracing implementation(projects.sentryJdbc) runtimeOnly(Config.TestLibs.hsqldb) + + testImplementation(projects.sentrySystemTestSupport) testImplementation(Config.Libs.springBoot3StarterTest) { exclude(group = "org.junit.vintage", module = "junit-vintage-engine") } @@ -123,13 +124,3 @@ tasks.named("test").configure { excludeTestsMatching("io.sentry.systemtest.*") } } - -apollo { - service("service") { - srcDir("src/test/graphql") - packageName.set("io.sentry.samples.graphql") - outputDirConnection { - connectToKotlinSourceSet("test") - } - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/graphql/greeting.graphql b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/graphql/greeting.graphql deleted file mode 100644 index 06c866a65fa..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/graphql/greeting.graphql +++ /dev/null @@ -1,3 +0,0 @@ -query GreetingQuery($name: String!) { - greeting(name: $name) -} diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/graphql/project.graphql b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/graphql/project.graphql deleted file mode 100644 index bff62ed2c2c..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/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-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/graphql/schema.graphqls b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/graphql/schema.graphqls deleted file mode 100644 index d76aca4756a..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/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-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/graphql/task.graphql b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/graphql/task.graphql deleted file mode 100644 index 11ae18574d3..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/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-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt index b60f2b113a3..b4122d32311 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt @@ -19,7 +19,7 @@ class GraphqlGreetingSystemTest { val response = testHelper.graphqlClient.greet("world") testHelper.ensureNoErrors(response) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "query GreetingQuery") } } @@ -32,7 +32,7 @@ class GraphqlGreetingSystemTest { testHelper.ensureErrorReceived { error -> error.message?.message?.startsWith("Unresolved RuntimeException for executionId ") ?: false } - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "query GreetingQuery") } } diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt index 8946284be43..6452bdaf1ca 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt @@ -23,7 +23,7 @@ class GraphqlProjectSystemTest { testHelper.ensureNoErrors(response) assertEquals("proj-slug", response?.data?.project?.slug) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "query ProjectQuery") } } @@ -34,7 +34,7 @@ class GraphqlProjectSystemTest { testHelper.ensureNoErrors(response) assertNotNull(response?.data?.addProject) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "mutation AddProjectMutation") } } @@ -48,7 +48,7 @@ class GraphqlProjectSystemTest { testHelper.ensureErrorReceived { error -> error.message?.message?.startsWith("Unresolved RuntimeException for executionId ") ?: false } - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "mutation AddProjectMutation") } } diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt index 2fba967c824..38343e5b0e5 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt @@ -30,7 +30,7 @@ class GraphqlTaskSystemTest { assertEquals("C3", firstTask.creatorId) assertEquals("C3", firstTask.creator?.id) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "query TasksAndAssigneesQuery") } } diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt index 8d83bde6309..4f7661dc4b3 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt @@ -1,9 +1,7 @@ package io.sentry.systemtest -import io.sentry.samples.spring.boot.jakarta.Person import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals @@ -21,9 +19,9 @@ class PersonSystemTest { fun `get person fails`() { val restClient = testHelper.restClient restClient.getPerson(1L) - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, restClient.lastKnownStatusCode) + assertEquals(500, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughOtelApi") && testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughSentryApi") } @@ -34,12 +32,12 @@ class PersonSystemTest { val restClient = testHelper.restClient val person = Person("firstA", "lastB") val returnedPerson = restClient.createPerson(person) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) assertEquals(person.firstName, returnedPerson!!.firstName) assertEquals(person.lastName, returnedPerson!!.lastName) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughOtelApi") && testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughSentryApi") } diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt index 4c8ee45ea64..80b9bd4f310 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt @@ -2,7 +2,6 @@ package io.sentry.systemtest import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals @@ -20,9 +19,9 @@ class TodoSystemTest { fun `get todo works`() { val restClient = testHelper.restClient restClient.getTodo(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "todoSpanOtelApi") && testHelper.doesTransactionContainSpanWithOp(transaction, "todoSpanSentryApi") && testHelper.doesTransactionContainSpanWithOp(transaction, "http.client") @@ -33,9 +32,9 @@ class TodoSystemTest { fun `get todo webclient works`() { val restClient = testHelper.restClient restClient.getTodoWebclient(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "http.client") } } @@ -44,9 +43,9 @@ class TodoSystemTest { fun `get todo restclient works`() { val restClient = testHelper.restClient restClient.getTodoRestClient(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "todoRestClientSpanOtelApi") && testHelper.doesTransactionContainSpanWithOp(transaction, "todoRestClientSpanSentryApi") && testHelper.doesTransactionContainSpanWithOp(transaction, "http.client") diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt deleted file mode 100644 index 0c11906292b..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.sentry.systemtest.graphql - -import com.apollographql.apollo3.ApolloClient -import com.apollographql.apollo3.api.ApolloResponse -import com.apollographql.apollo3.api.Mutation -import com.apollographql.apollo3.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? { - return executeQuery(GreetingQuery(name)) - } - - fun project(slug: String): ApolloResponse? { - return executeQuery(ProjectQuery(slug)) - } - - fun tasksAndAssignees(slug: String): ApolloResponse? { - return executeQuery(TasksAndAssigneesQuery(slug)) - } - - fun addProject(slug: String): ApolloResponse? { - return 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-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt deleted file mode 100644 index 17eea1a0084..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.sentry.systemtest.util - -import org.springframework.http.client.BufferingClientHttpRequestFactory -import org.springframework.web.client.RestTemplate - -open class LoggingInsecureRestClient { - - protected fun restTemplate(): RestTemplate { - return RestTemplate().also { - it.requestFactory = BufferingClientHttpRequestFactory(it.requestFactory) - } - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt deleted file mode 100644 index 1b1d16c841f..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt +++ /dev/null @@ -1,76 +0,0 @@ -package io.sentry.systemtest.util - -import io.sentry.samples.spring.boot.jakarta.Person -import io.sentry.samples.spring.boot.jakarta.Todo -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatusCode -import org.springframework.web.client.HttpStatusCodeException - -class RestTestClient(private val backendBaseUrl: String) : LoggingInsecureRestClient() { - var lastKnownStatusCode: HttpStatusCode? = 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - fun createPerson(person: Person): Person? { - return try { - val response = restTemplate().exchange("$backendBaseUrl/person/", HttpMethod.POST, entityWithAuth(person), Person::class.java, person) - lastKnownStatusCode = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - private fun entityWithAuth(request: Any? = null): HttpEntity { - val headers = HttpHeaders().also { - it.setBasicAuth("user", "password") - } - - return HttpEntity(request, headers) - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt deleted file mode 100644 index 7ef1699f122..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.sentry.systemtest.util - -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod - -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!! - } - - fun reset() { - restTemplate().exchange("$baseUrl/reset", HttpMethod.GET, entityWithAuth(), Any::class.java) - } - - fun getEnvelopes(): EnvelopesReceived { - val response = restTemplate().exchange("$baseUrl/envelopes-received", HttpMethod.GET, entityWithAuth(), EnvelopesReceived::class.java) - return response.body!! - } - - private fun entityWithAuth(request: Any? = null): HttpEntity { - val headers = HttpHeaders() - return HttpEntity(request, headers) - } -} - -class EnvelopeCounts { - val envelopes: Long? = null - - override fun toString(): String { - return "EnvelopeCounts{envelopes=$envelopes}" - } -} - -class EnvelopesReceived { - val envelopes: List? = null - - override fun toString(): String { - return "EnvelopesReceived{envelopes=$envelopes}" - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt b/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt deleted file mode 100644 index 12960f4c528..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt +++ /dev/null @@ -1,162 +0,0 @@ -package io.sentry.systemtest.util - -import com.apollographql.apollo3.api.ApolloResponse -import com.apollographql.apollo3.api.Operation -import io.sentry.JsonSerializer -import io.sentry.SentryEvent -import io.sentry.SentryItemType -import io.sentry.SentryOptions -import io.sentry.protocol.SentrySpan -import io.sentry.protocol.SentryTransaction -import io.sentry.systemtest.graphql.GraphqlTestClient -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 - - 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(callback: ((String) -> Boolean)) { - Thread.sleep(10000) - val envelopes = sentryClient.getEnvelopes() - assertNotNull(envelopes.envelopes) - envelopes.envelopes.forEach { envelopeString -> - val didMatch = callback(envelopeString) - if (didMatch) { - return - } - } - throw RuntimeException("Unable to find matching envelope received by relay") - } - - fun ensureTransactionReceived(callback: ((SentryTransaction) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> - val deserializeEnvelope = - jsonSerializer.deserializeEnvelope(envelopeString.byteInputStream()) - if (deserializeEnvelope == null) { - return@ensureEnvelopeReceived false - } - - val transactionItem = - deserializeEnvelope.items.firstOrNull { it.header.type == SentryItemType.Transaction } - if (transactionItem == null) { - return@ensureEnvelopeReceived false - } - - val transaction = transactionItem.getTransaction(jsonSerializer) - if (transaction == null) { - return@ensureEnvelopeReceived false - } - - callback(transaction) - } - } - - fun ensureErrorReceived(callback: ((SentryEvent) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> - val deserializeEnvelope = - jsonSerializer.deserializeEnvelope(envelopeString.byteInputStream()) - if (deserializeEnvelope == null) { - return@ensureEnvelopeReceived false - } - - val errorItem = - deserializeEnvelope.items.firstOrNull { it.header.type == SentryItemType.Event } - if (errorItem == null) { - return@ensureEnvelopeReceived false - } - - val error = errorItem.getEvent(jsonSerializer) - if (error == null) { - 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 -> - transaction.spans.forEach { span -> - val callbackResult = callback(span) - if (callbackResult) { - return@ensureTransactionReceived true - } - } - false - } - } - - fun reset() { - sentryClient.reset() - } - - fun logObject(obj: Any?) { - obj ?: return - PrintWriter(System.out).use { - jsonSerializer.serialize(obj, it) - } - } - - 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 { - val span = transaction.spans.firstOrNull { span -> span.op == op } - if (span == null) { - println("Unable to find span with op $op in transaction:") - logObject(transaction) - return false - } - - return true - } - - fun doesTransactionContainSpanWithDescription(transaction: SentryTransaction, description: String): Boolean { - val span = transaction.spans.firstOrNull { span -> span.description == description } - if (span == null) { - println("Unable to find span with description $description in transaction:") - logObject(transaction) - return false - } - - return true - } -} 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 242859656c3..11e6b613466 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot-jakarta/build.gradle.kts @@ -6,7 +6,6 @@ plugins { id(Config.BuildPlugins.springDependencyManagement) version Config.BuildPlugins.springDependencyManagementVersion kotlin("jvm") kotlin("plugin.spring") version Config.kotlinVersion - id("com.apollographql.apollo3") version "3.8.2" } group = "io.sentry.sample.spring-boot-jakarta" @@ -56,6 +55,8 @@ dependencies { // database query tracing implementation(projects.sentryJdbc) runtimeOnly(Config.TestLibs.hsqldb) + + testImplementation(projects.sentrySystemTestSupport) testImplementation(Config.Libs.springBoot3StarterTest) { exclude(group = "org.junit.vintage", module = "junit-vintage-engine") } @@ -97,13 +98,3 @@ tasks.named("test").configure { excludeTestsMatching("io.sentry.systemtest.*") } } - -apollo { - service("service") { - srcDir("src/test/graphql") - packageName.set("io.sentry.samples.graphql") - outputDirConnection { - connectToKotlinSourceSet("test") - } - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/graphql/greeting.graphql b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/graphql/greeting.graphql deleted file mode 100644 index 06c866a65fa..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/graphql/greeting.graphql +++ /dev/null @@ -1,3 +0,0 @@ -query GreetingQuery($name: String!) { - greeting(name: $name) -} diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/graphql/project.graphql b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/graphql/project.graphql deleted file mode 100644 index bff62ed2c2c..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/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-samples/sentry-samples-spring-boot-jakarta/src/test/graphql/schema.graphqls b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/graphql/schema.graphqls deleted file mode 100644 index d76aca4756a..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/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-samples/sentry-samples-spring-boot-jakarta/src/test/graphql/task.graphql b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/graphql/task.graphql deleted file mode 100644 index 11ae18574d3..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/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-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt index 769ae399bf0..5681c421a28 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt @@ -19,7 +19,7 @@ class GraphqlGreetingSystemTest { val response = testHelper.graphqlClient.greet("world") testHelper.ensureNoErrors(response) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Query.greeting") } } @@ -32,7 +32,7 @@ class GraphqlGreetingSystemTest { testHelper.ensureErrorReceived { error -> error.message?.message?.startsWith("Unresolved RuntimeException for executionId ") ?: false } - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Query.greeting") } } diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt index 74b196e33b6..bfa38fead33 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt @@ -23,7 +23,7 @@ class GraphqlProjectSystemTest { testHelper.ensureNoErrors(response) assertEquals("proj-slug", response?.data?.project?.slug) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Query.project") } } @@ -34,7 +34,7 @@ class GraphqlProjectSystemTest { testHelper.ensureNoErrors(response) assertNotNull(response?.data?.addProject) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Mutation.addProject") } } @@ -48,7 +48,7 @@ class GraphqlProjectSystemTest { testHelper.ensureErrorReceived { error -> error.message?.message?.startsWith("Unresolved RuntimeException for executionId ") ?: false } - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Mutation.addProject") } } diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt index cf2aebfd090..0f634f309bd 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt @@ -30,7 +30,7 @@ class GraphqlTaskSystemTest { assertEquals("C3", firstTask.creatorId) assertEquals("C3", firstTask.creator?.id) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Query.tasks") && testHelper.doesTransactionContainSpanWithDescription(transaction, "Task.assignee") && testHelper.doesTransactionContainSpanWithDescription(transaction, "Task.creator") diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt index e4a388ef529..c190b86d6b0 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt @@ -1,9 +1,7 @@ package io.sentry.systemtest -import io.sentry.samples.spring.boot.jakarta.Person import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals @@ -21,9 +19,9 @@ class PersonSystemTest { fun `get person fails`() { val restClient = testHelper.restClient restClient.getPerson(1L) - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, restClient.lastKnownStatusCode) + assertEquals(500, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionHaveOp(transaction, "http.server") } } @@ -33,12 +31,12 @@ class PersonSystemTest { val restClient = testHelper.restClient val person = Person("firstA", "lastB") val returnedPerson = restClient.createPerson(person) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) assertEquals(person.firstName, returnedPerson!!.firstName) assertEquals(person.lastName, returnedPerson!!.lastName) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "PersonService.create") && testHelper.doesTransactionContainSpanWithOp(transaction, "db.query") } diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt index 9893bcb3966..3ef84872a81 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt @@ -2,7 +2,6 @@ package io.sentry.systemtest import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals @@ -20,9 +19,9 @@ class TodoSystemTest { fun `get todo works`() { val restClient = testHelper.restClient restClient.getTodo(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "http.client") } } @@ -31,9 +30,9 @@ class TodoSystemTest { fun `get todo webclient works`() { val restClient = testHelper.restClient restClient.getTodoWebclient(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "http.client") } } @@ -42,9 +41,9 @@ class TodoSystemTest { fun `get todo restclient works`() { val restClient = testHelper.restClient restClient.getTodoRestClient(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "http.client") } } diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt deleted file mode 100644 index 0c11906292b..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.sentry.systemtest.graphql - -import com.apollographql.apollo3.ApolloClient -import com.apollographql.apollo3.api.ApolloResponse -import com.apollographql.apollo3.api.Mutation -import com.apollographql.apollo3.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? { - return executeQuery(GreetingQuery(name)) - } - - fun project(slug: String): ApolloResponse? { - return executeQuery(ProjectQuery(slug)) - } - - fun tasksAndAssignees(slug: String): ApolloResponse? { - return executeQuery(TasksAndAssigneesQuery(slug)) - } - - fun addProject(slug: String): ApolloResponse? { - return 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-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt deleted file mode 100644 index 17eea1a0084..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.sentry.systemtest.util - -import org.springframework.http.client.BufferingClientHttpRequestFactory -import org.springframework.web.client.RestTemplate - -open class LoggingInsecureRestClient { - - protected fun restTemplate(): RestTemplate { - return RestTemplate().also { - it.requestFactory = BufferingClientHttpRequestFactory(it.requestFactory) - } - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt deleted file mode 100644 index 1b1d16c841f..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt +++ /dev/null @@ -1,76 +0,0 @@ -package io.sentry.systemtest.util - -import io.sentry.samples.spring.boot.jakarta.Person -import io.sentry.samples.spring.boot.jakarta.Todo -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatusCode -import org.springframework.web.client.HttpStatusCodeException - -class RestTestClient(private val backendBaseUrl: String) : LoggingInsecureRestClient() { - var lastKnownStatusCode: HttpStatusCode? = 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - fun createPerson(person: Person): Person? { - return try { - val response = restTemplate().exchange("$backendBaseUrl/person/", HttpMethod.POST, entityWithAuth(person), Person::class.java, person) - lastKnownStatusCode = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - private fun entityWithAuth(request: Any? = null): HttpEntity { - val headers = HttpHeaders().also { - it.setBasicAuth("user", "password") - } - - return HttpEntity(request, headers) - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt deleted file mode 100644 index 7ef1699f122..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.sentry.systemtest.util - -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod - -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!! - } - - fun reset() { - restTemplate().exchange("$baseUrl/reset", HttpMethod.GET, entityWithAuth(), Any::class.java) - } - - fun getEnvelopes(): EnvelopesReceived { - val response = restTemplate().exchange("$baseUrl/envelopes-received", HttpMethod.GET, entityWithAuth(), EnvelopesReceived::class.java) - return response.body!! - } - - private fun entityWithAuth(request: Any? = null): HttpEntity { - val headers = HttpHeaders() - return HttpEntity(request, headers) - } -} - -class EnvelopeCounts { - val envelopes: Long? = null - - override fun toString(): String { - return "EnvelopeCounts{envelopes=$envelopes}" - } -} - -class EnvelopesReceived { - val envelopes: List? = null - - override fun toString(): String { - return "EnvelopesReceived{envelopes=$envelopes}" - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt b/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt deleted file mode 100644 index 1017d847348..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-jakarta/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt +++ /dev/null @@ -1,173 +0,0 @@ -package io.sentry.systemtest.util - -import com.apollographql.apollo3.api.ApolloResponse -import com.apollographql.apollo3.api.Operation -import io.sentry.JsonSerializer -import io.sentry.SentryEvent -import io.sentry.SentryItemType -import io.sentry.SentryOptions -import io.sentry.protocol.SentrySpan -import io.sentry.protocol.SentryTransaction -import io.sentry.systemtest.graphql.GraphqlTestClient -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 - - 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(callback: ((String) -> Boolean)) { - Thread.sleep(10000) - val envelopes = sentryClient.getEnvelopes() - assertNotNull(envelopes.envelopes) - envelopes.envelopes.forEach { envelopeString -> - val didMatch = callback(envelopeString) - if (didMatch) { - return - } - } - throw RuntimeException("Unable to find matching envelope received by relay") - } - - fun ensureTransactionReceived(callback: ((SentryTransaction) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> - val deserializeEnvelope = - jsonSerializer.deserializeEnvelope(envelopeString.byteInputStream()) - if (deserializeEnvelope == null) { - return@ensureEnvelopeReceived false - } - - val transactionItem = - deserializeEnvelope.items.firstOrNull { it.header.type == SentryItemType.Transaction } - if (transactionItem == null) { - return@ensureEnvelopeReceived false - } - - val transaction = transactionItem.getTransaction(jsonSerializer) - if (transaction == null) { - return@ensureEnvelopeReceived false - } - - callback(transaction) - } - } - - fun ensureErrorReceived(callback: ((SentryEvent) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> - val deserializeEnvelope = - jsonSerializer.deserializeEnvelope(envelopeString.byteInputStream()) - if (deserializeEnvelope == null) { - return@ensureEnvelopeReceived false - } - - val errorItem = - deserializeEnvelope.items.firstOrNull { it.header.type == SentryItemType.Event } - if (errorItem == null) { - return@ensureEnvelopeReceived false - } - - val error = errorItem.getEvent(jsonSerializer) - if (error == null) { - 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 -> - transaction.spans.forEach { span -> - val callbackResult = callback(span) - if (callbackResult) { - return@ensureTransactionReceived true - } - } - false - } - } - - fun reset() { - sentryClient.reset() - } - - fun logObject(obj: Any?) { - obj ?: return - PrintWriter(System.out).use { - jsonSerializer.serialize(obj, it) - } - } - - 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 { - val span = transaction.spans.firstOrNull { span -> span.op == op } - if (span == null) { - println("Unable to find span with op $op in transaction:") - logObject(transaction) - return false - } - - return true - } - - fun doesTransactionContainSpanWithDescription(transaction: SentryTransaction, description: String): Boolean { - val span = transaction.spans.firstOrNull { span -> span.description == description } - if (span == null) { - println("Unable to find span with description $description in transaction:") - logObject(transaction) - return false - } - - return true - } - - fun doesTransactionHaveOp(transaction: SentryTransaction, op: String): Boolean { - val matches = transaction.contexts.trace?.operation == op - if (!matches) { - println("Unable to find transaction with op $op:") - logObject(transaction) - return false - } - - return true - } -} 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 c6dd41951cc..fa30b6d3b16 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 @@ -6,7 +6,6 @@ plugins { id(Config.BuildPlugins.springDependencyManagement) version Config.BuildPlugins.springDependencyManagementVersion kotlin("jvm") kotlin("plugin.spring") version Config.kotlinVersion - id("com.apollographql.apollo3") version "3.8.2" } group = "io.sentry.sample.spring-boot" @@ -57,6 +56,8 @@ dependencies { // database query tracing implementation(projects.sentryJdbc) runtimeOnly(Config.TestLibs.hsqldb) + + testImplementation(projects.sentrySystemTestSupport) testImplementation(Config.Libs.springBootStarterTest) { exclude(group = "org.junit.vintage", module = "junit-vintage-engine") } @@ -104,13 +105,3 @@ tasks.named("test").configure { excludeTestsMatching("io.sentry.systemtest.*") } } - -apollo { - service("service") { - srcDir("src/test/graphql") - packageName.set("io.sentry.samples.graphql") - outputDirConnection { - connectToKotlinSourceSet("test") - } - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/graphql/greeting.graphql b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/graphql/greeting.graphql deleted file mode 100644 index 06c866a65fa..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/graphql/greeting.graphql +++ /dev/null @@ -1,3 +0,0 @@ -query GreetingQuery($name: String!) { - greeting(name: $name) -} diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/graphql/project.graphql b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/graphql/project.graphql deleted file mode 100644 index bff62ed2c2c..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/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-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/graphql/schema.graphqls b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/graphql/schema.graphqls deleted file mode 100644 index d76aca4756a..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/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-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/graphql/task.graphql b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/graphql/task.graphql deleted file mode 100644 index 11ae18574d3..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/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-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt index 769ae399bf0..5681c421a28 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt @@ -19,7 +19,7 @@ class GraphqlGreetingSystemTest { val response = testHelper.graphqlClient.greet("world") testHelper.ensureNoErrors(response) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Query.greeting") } } @@ -32,7 +32,7 @@ class GraphqlGreetingSystemTest { testHelper.ensureErrorReceived { error -> error.message?.message?.startsWith("Unresolved RuntimeException for executionId ") ?: false } - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Query.greeting") } } diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt index 74b196e33b6..bfa38fead33 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt @@ -23,7 +23,7 @@ class GraphqlProjectSystemTest { testHelper.ensureNoErrors(response) assertEquals("proj-slug", response?.data?.project?.slug) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Query.project") } } @@ -34,7 +34,7 @@ class GraphqlProjectSystemTest { testHelper.ensureNoErrors(response) assertNotNull(response?.data?.addProject) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Mutation.addProject") } } @@ -48,7 +48,7 @@ class GraphqlProjectSystemTest { testHelper.ensureErrorReceived { error -> error.message?.message?.startsWith("Unresolved RuntimeException for executionId ") ?: false } - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Mutation.addProject") } } diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt index 7a9283ac05a..7b8a1471542 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt @@ -30,7 +30,7 @@ class GraphqlTaskSystemTest { assertEquals("C3", firstTask.creatorId) assertEquals("C3", firstTask.creator?.id) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Query.tasks") } } diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt index 9309529ce44..4f7661dc4b3 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt @@ -1,9 +1,7 @@ package io.sentry.systemtest -import io.sentry.samples.spring.boot.Person import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals @@ -21,9 +19,9 @@ class PersonSystemTest { fun `get person fails`() { val restClient = testHelper.restClient restClient.getPerson(1L) - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, restClient.lastKnownStatusCode) + assertEquals(500, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughOtelApi") && testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughSentryApi") } @@ -34,12 +32,12 @@ class PersonSystemTest { val restClient = testHelper.restClient val person = Person("firstA", "lastB") val returnedPerson = restClient.createPerson(person) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) assertEquals(person.firstName, returnedPerson!!.firstName) assertEquals(person.lastName, returnedPerson!!.lastName) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughOtelApi") && testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughSentryApi") } diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt index a48ea15fdd5..8b472ede78e 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt @@ -2,7 +2,6 @@ package io.sentry.systemtest import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals @@ -20,9 +19,9 @@ class TodoSystemTest { fun `get todo works`() { val restClient = testHelper.restClient restClient.getTodo(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "todoSpanOtelApi") && testHelper.doesTransactionContainSpanWithOp(transaction, "todoSpanSentryApi") && testHelper.doesTransactionContainSpanWithOp(transaction, "http.client") @@ -33,9 +32,9 @@ class TodoSystemTest { fun `get todo webclient works`() { val restClient = testHelper.restClient restClient.getTodoWebclient(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "http.client") } } diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt deleted file mode 100644 index 0c11906292b..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.sentry.systemtest.graphql - -import com.apollographql.apollo3.ApolloClient -import com.apollographql.apollo3.api.ApolloResponse -import com.apollographql.apollo3.api.Mutation -import com.apollographql.apollo3.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? { - return executeQuery(GreetingQuery(name)) - } - - fun project(slug: String): ApolloResponse? { - return executeQuery(ProjectQuery(slug)) - } - - fun tasksAndAssignees(slug: String): ApolloResponse? { - return executeQuery(TasksAndAssigneesQuery(slug)) - } - - fun addProject(slug: String): ApolloResponse? { - return 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-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt deleted file mode 100644 index 0577f0eef21..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt +++ /dev/null @@ -1,32 +0,0 @@ -package io.sentry.systemtest.util - -import org.apache.http.impl.client.HttpClients -import org.springframework.http.client.BufferingClientHttpRequestFactory -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory -import org.springframework.web.client.RestTemplate - -open class LoggingInsecureRestClient { - - protected fun restTemplate(): RestTemplate { - val requestFactory = BufferingClientHttpRequestFactory( - HttpComponentsClientHttpRequestFactory(HttpClients.createDefault()) - ) - return RestTemplate(requestFactory).also { - it.messageConverters.add(0, jacksonConverter()) - } - } - - private fun jacksonConverter(): org.springframework.http.converter.json.MappingJackson2HttpMessageConverter { - val converter = org.springframework.http.converter.json.MappingJackson2HttpMessageConverter() - converter.objectMapper = objectMapper() - return converter - } - - private fun objectMapper(): com.fasterxml.jackson.databind.ObjectMapper { - val builder = org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.json() - val objectMapper: com.fasterxml.jackson.databind.ObjectMapper = builder.createXmlMapper(false).build() - objectMapper.registerModule(com.fasterxml.jackson.datatype.jsr310.JavaTimeModule()) - objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) - return objectMapper - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt deleted file mode 100644 index f5d5bd7ee38..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt +++ /dev/null @@ -1,65 +0,0 @@ -package io.sentry.systemtest.util - -import io.sentry.samples.spring.boot.Person -import io.sentry.samples.spring.boot.Todo -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus -import org.springframework.web.client.HttpStatusCodeException - -class RestTestClient(private val backendBaseUrl: String) : LoggingInsecureRestClient() { - var lastKnownStatusCode: HttpStatus? = 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - fun createPerson(person: Person): Person? { - return try { - val response = restTemplate().exchange("$backendBaseUrl/person/", HttpMethod.POST, entityWithAuth(person), Person::class.java, person) - lastKnownStatusCode = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - private fun entityWithAuth(request: Any? = null): HttpEntity { - val headers = HttpHeaders().also { - it.setBasicAuth("user", "password") - } - - return HttpEntity(request, headers) - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt deleted file mode 100644 index 7ef1699f122..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.sentry.systemtest.util - -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod - -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!! - } - - fun reset() { - restTemplate().exchange("$baseUrl/reset", HttpMethod.GET, entityWithAuth(), Any::class.java) - } - - fun getEnvelopes(): EnvelopesReceived { - val response = restTemplate().exchange("$baseUrl/envelopes-received", HttpMethod.GET, entityWithAuth(), EnvelopesReceived::class.java) - return response.body!! - } - - private fun entityWithAuth(request: Any? = null): HttpEntity { - val headers = HttpHeaders() - return HttpEntity(request, headers) - } -} - -class EnvelopeCounts { - val envelopes: Long? = null - - override fun toString(): String { - return "EnvelopeCounts{envelopes=$envelopes}" - } -} - -class EnvelopesReceived { - val envelopes: List? = null - - override fun toString(): String { - return "EnvelopesReceived{envelopes=$envelopes}" - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt deleted file mode 100644 index 1017d847348..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt +++ /dev/null @@ -1,173 +0,0 @@ -package io.sentry.systemtest.util - -import com.apollographql.apollo3.api.ApolloResponse -import com.apollographql.apollo3.api.Operation -import io.sentry.JsonSerializer -import io.sentry.SentryEvent -import io.sentry.SentryItemType -import io.sentry.SentryOptions -import io.sentry.protocol.SentrySpan -import io.sentry.protocol.SentryTransaction -import io.sentry.systemtest.graphql.GraphqlTestClient -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 - - 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(callback: ((String) -> Boolean)) { - Thread.sleep(10000) - val envelopes = sentryClient.getEnvelopes() - assertNotNull(envelopes.envelopes) - envelopes.envelopes.forEach { envelopeString -> - val didMatch = callback(envelopeString) - if (didMatch) { - return - } - } - throw RuntimeException("Unable to find matching envelope received by relay") - } - - fun ensureTransactionReceived(callback: ((SentryTransaction) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> - val deserializeEnvelope = - jsonSerializer.deserializeEnvelope(envelopeString.byteInputStream()) - if (deserializeEnvelope == null) { - return@ensureEnvelopeReceived false - } - - val transactionItem = - deserializeEnvelope.items.firstOrNull { it.header.type == SentryItemType.Transaction } - if (transactionItem == null) { - return@ensureEnvelopeReceived false - } - - val transaction = transactionItem.getTransaction(jsonSerializer) - if (transaction == null) { - return@ensureEnvelopeReceived false - } - - callback(transaction) - } - } - - fun ensureErrorReceived(callback: ((SentryEvent) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> - val deserializeEnvelope = - jsonSerializer.deserializeEnvelope(envelopeString.byteInputStream()) - if (deserializeEnvelope == null) { - return@ensureEnvelopeReceived false - } - - val errorItem = - deserializeEnvelope.items.firstOrNull { it.header.type == SentryItemType.Event } - if (errorItem == null) { - return@ensureEnvelopeReceived false - } - - val error = errorItem.getEvent(jsonSerializer) - if (error == null) { - 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 -> - transaction.spans.forEach { span -> - val callbackResult = callback(span) - if (callbackResult) { - return@ensureTransactionReceived true - } - } - false - } - } - - fun reset() { - sentryClient.reset() - } - - fun logObject(obj: Any?) { - obj ?: return - PrintWriter(System.out).use { - jsonSerializer.serialize(obj, it) - } - } - - 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 { - val span = transaction.spans.firstOrNull { span -> span.op == op } - if (span == null) { - println("Unable to find span with op $op in transaction:") - logObject(transaction) - return false - } - - return true - } - - fun doesTransactionContainSpanWithDescription(transaction: SentryTransaction, description: String): Boolean { - val span = transaction.spans.firstOrNull { span -> span.description == description } - if (span == null) { - println("Unable to find span with description $description in transaction:") - logObject(transaction) - return false - } - - return true - } - - fun doesTransactionHaveOp(transaction: SentryTransaction, op: String): Boolean { - val matches = transaction.contexts.trace?.operation == op - if (!matches) { - println("Unable to find transaction with op $op:") - logObject(transaction) - return false - } - - return true - } -} 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 be159d82445..5bf0d001881 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry/build.gradle.kts @@ -7,7 +7,6 @@ plugins { id(Config.BuildPlugins.springDependencyManagement) version Config.BuildPlugins.springDependencyManagementVersion kotlin("jvm") kotlin("plugin.spring") version Config.kotlinVersion - id("com.apollographql.apollo3") version "3.8.2" } group = "io.sentry.sample.spring-boot" @@ -58,6 +57,8 @@ dependencies { // database query tracing implementation(projects.sentryJdbc) runtimeOnly(Config.TestLibs.hsqldb) + + testImplementation(projects.sentrySystemTestSupport) testImplementation(Config.Libs.springBootStarterTest) { exclude(group = "org.junit.vintage", module = "junit-vintage-engine") } @@ -124,13 +125,3 @@ tasks.named("test").configure { excludeTestsMatching("io.sentry.systemtest.*") } } - -apollo { - service("service") { - srcDir("src/test/graphql") - packageName.set("io.sentry.samples.graphql") - outputDirConnection { - connectToKotlinSourceSet("test") - } - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/graphql/greeting.graphql b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/graphql/greeting.graphql deleted file mode 100644 index 06c866a65fa..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/graphql/greeting.graphql +++ /dev/null @@ -1,3 +0,0 @@ -query GreetingQuery($name: String!) { - greeting(name: $name) -} diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/graphql/project.graphql b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/graphql/project.graphql deleted file mode 100644 index bff62ed2c2c..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/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-samples/sentry-samples-spring-boot-opentelemetry/src/test/graphql/schema.graphqls b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/graphql/schema.graphqls deleted file mode 100644 index d76aca4756a..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/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-samples/sentry-samples-spring-boot-opentelemetry/src/test/graphql/task.graphql b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/graphql/task.graphql deleted file mode 100644 index 11ae18574d3..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/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-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt index b60f2b113a3..b4122d32311 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt @@ -19,7 +19,7 @@ class GraphqlGreetingSystemTest { val response = testHelper.graphqlClient.greet("world") testHelper.ensureNoErrors(response) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "query GreetingQuery") } } @@ -32,7 +32,7 @@ class GraphqlGreetingSystemTest { testHelper.ensureErrorReceived { error -> error.message?.message?.startsWith("Unresolved RuntimeException for executionId ") ?: false } - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "query GreetingQuery") } } diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt index 8946284be43..6452bdaf1ca 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt @@ -23,7 +23,7 @@ class GraphqlProjectSystemTest { testHelper.ensureNoErrors(response) assertEquals("proj-slug", response?.data?.project?.slug) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "query ProjectQuery") } } @@ -34,7 +34,7 @@ class GraphqlProjectSystemTest { testHelper.ensureNoErrors(response) assertNotNull(response?.data?.addProject) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "mutation AddProjectMutation") } } @@ -48,7 +48,7 @@ class GraphqlProjectSystemTest { testHelper.ensureErrorReceived { error -> error.message?.message?.startsWith("Unresolved RuntimeException for executionId ") ?: false } - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "mutation AddProjectMutation") } } diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt index 2fba967c824..38343e5b0e5 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt @@ -30,7 +30,7 @@ class GraphqlTaskSystemTest { assertEquals("C3", firstTask.creatorId) assertEquals("C3", firstTask.creator?.id) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "query TasksAndAssigneesQuery") } } diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt index cfa459213c3..b0807f3fbc1 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt @@ -1,9 +1,7 @@ package io.sentry.systemtest -import io.sentry.samples.spring.boot.Person import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals @@ -21,9 +19,9 @@ class PersonSystemTest { fun `get person fails`() { val restClient = testHelper.restClient restClient.getPerson(1L) - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, restClient.lastKnownStatusCode) + assertEquals(500, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughOtelApi") && testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughSentryApi") } @@ -34,12 +32,12 @@ class PersonSystemTest { val restClient = testHelper.restClient val person = Person("firstA", "lastB") val returnedPerson = restClient.createPerson(person) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) assertEquals(person.firstName, returnedPerson!!.firstName) assertEquals(person.lastName, returnedPerson!!.lastName) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughOtelApi") && testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughSentryApi") } @@ -56,12 +54,12 @@ class PersonSystemTest { "baggage" to "sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rate=1,sentry-trace_id=f9118105af4a2d42b4124532cd1065ff,sentry-transaction=HTTP%20GET" ) ) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) assertEquals(person.firstName, returnedPerson!!.firstName) assertEquals(person.lastName, returnedPerson!!.lastName) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughOtelApi") && testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughSentryApi") } @@ -78,12 +76,12 @@ class PersonSystemTest { "baggage" to "sentry-public_key=502f25099c204a2fbf4cb16edc5975d1,sentry-sample_rate=1,sentry-trace_id=f9118105af4a2d42b4124532cd1065ff,sentry-transaction=HTTP%20GET" ) ) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) assertEquals(person.firstName, returnedPerson!!.firstName) assertEquals(person.lastName, returnedPerson!!.lastName) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughOtelApi") && testHelper.doesTransactionContainSpanWithOp(transaction, "spanCreatedThroughSentryApi") } diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt index a48ea15fdd5..8b472ede78e 100644 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt @@ -2,7 +2,6 @@ package io.sentry.systemtest import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals @@ -20,9 +19,9 @@ class TodoSystemTest { fun `get todo works`() { val restClient = testHelper.restClient restClient.getTodo(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "todoSpanOtelApi") && testHelper.doesTransactionContainSpanWithOp(transaction, "todoSpanSentryApi") && testHelper.doesTransactionContainSpanWithOp(transaction, "http.client") @@ -33,9 +32,9 @@ class TodoSystemTest { fun `get todo webclient works`() { val restClient = testHelper.restClient restClient.getTodoWebclient(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "http.client") } } diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt deleted file mode 100644 index 0c11906292b..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.sentry.systemtest.graphql - -import com.apollographql.apollo3.ApolloClient -import com.apollographql.apollo3.api.ApolloResponse -import com.apollographql.apollo3.api.Mutation -import com.apollographql.apollo3.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? { - return executeQuery(GreetingQuery(name)) - } - - fun project(slug: String): ApolloResponse? { - return executeQuery(ProjectQuery(slug)) - } - - fun tasksAndAssignees(slug: String): ApolloResponse? { - return executeQuery(TasksAndAssigneesQuery(slug)) - } - - fun addProject(slug: String): ApolloResponse? { - return 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-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt deleted file mode 100644 index 0577f0eef21..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt +++ /dev/null @@ -1,32 +0,0 @@ -package io.sentry.systemtest.util - -import org.apache.http.impl.client.HttpClients -import org.springframework.http.client.BufferingClientHttpRequestFactory -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory -import org.springframework.web.client.RestTemplate - -open class LoggingInsecureRestClient { - - protected fun restTemplate(): RestTemplate { - val requestFactory = BufferingClientHttpRequestFactory( - HttpComponentsClientHttpRequestFactory(HttpClients.createDefault()) - ) - return RestTemplate(requestFactory).also { - it.messageConverters.add(0, jacksonConverter()) - } - } - - private fun jacksonConverter(): org.springframework.http.converter.json.MappingJackson2HttpMessageConverter { - val converter = org.springframework.http.converter.json.MappingJackson2HttpMessageConverter() - converter.objectMapper = objectMapper() - return converter - } - - private fun objectMapper(): com.fasterxml.jackson.databind.ObjectMapper { - val builder = org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.json() - val objectMapper: com.fasterxml.jackson.databind.ObjectMapper = builder.createXmlMapper(false).build() - objectMapper.registerModule(com.fasterxml.jackson.datatype.jsr310.JavaTimeModule()) - objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) - return objectMapper - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt deleted file mode 100644 index 1c4eef63f78..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt +++ /dev/null @@ -1,68 +0,0 @@ -package io.sentry.systemtest.util - -import io.sentry.samples.spring.boot.Person -import io.sentry.samples.spring.boot.Todo -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus -import org.springframework.web.client.HttpStatusCodeException - -class RestTestClient(private val backendBaseUrl: String) : LoggingInsecureRestClient() { - var lastKnownStatusCode: HttpStatus? = 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - private fun entityWithAuth(request: Any? = null, extraHeaders: Map? = null): HttpEntity { - val headers = HttpHeaders().also { httpHeaders -> - httpHeaders.setBasicAuth("user", "password") - extraHeaders?.forEach { key, value -> - httpHeaders.set(key, value) - } - } - - return HttpEntity(request, headers) - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt deleted file mode 100644 index 7ef1699f122..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.sentry.systemtest.util - -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod - -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!! - } - - fun reset() { - restTemplate().exchange("$baseUrl/reset", HttpMethod.GET, entityWithAuth(), Any::class.java) - } - - fun getEnvelopes(): EnvelopesReceived { - val response = restTemplate().exchange("$baseUrl/envelopes-received", HttpMethod.GET, entityWithAuth(), EnvelopesReceived::class.java) - return response.body!! - } - - private fun entityWithAuth(request: Any? = null): HttpEntity { - val headers = HttpHeaders() - return HttpEntity(request, headers) - } -} - -class EnvelopeCounts { - val envelopes: Long? = null - - override fun toString(): String { - return "EnvelopeCounts{envelopes=$envelopes}" - } -} - -class EnvelopesReceived { - val envelopes: List? = null - - override fun toString(): String { - return "EnvelopesReceived{envelopes=$envelopes}" - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt b/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt deleted file mode 100644 index 1017d847348..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-opentelemetry/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt +++ /dev/null @@ -1,173 +0,0 @@ -package io.sentry.systemtest.util - -import com.apollographql.apollo3.api.ApolloResponse -import com.apollographql.apollo3.api.Operation -import io.sentry.JsonSerializer -import io.sentry.SentryEvent -import io.sentry.SentryItemType -import io.sentry.SentryOptions -import io.sentry.protocol.SentrySpan -import io.sentry.protocol.SentryTransaction -import io.sentry.systemtest.graphql.GraphqlTestClient -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 - - 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(callback: ((String) -> Boolean)) { - Thread.sleep(10000) - val envelopes = sentryClient.getEnvelopes() - assertNotNull(envelopes.envelopes) - envelopes.envelopes.forEach { envelopeString -> - val didMatch = callback(envelopeString) - if (didMatch) { - return - } - } - throw RuntimeException("Unable to find matching envelope received by relay") - } - - fun ensureTransactionReceived(callback: ((SentryTransaction) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> - val deserializeEnvelope = - jsonSerializer.deserializeEnvelope(envelopeString.byteInputStream()) - if (deserializeEnvelope == null) { - return@ensureEnvelopeReceived false - } - - val transactionItem = - deserializeEnvelope.items.firstOrNull { it.header.type == SentryItemType.Transaction } - if (transactionItem == null) { - return@ensureEnvelopeReceived false - } - - val transaction = transactionItem.getTransaction(jsonSerializer) - if (transaction == null) { - return@ensureEnvelopeReceived false - } - - callback(transaction) - } - } - - fun ensureErrorReceived(callback: ((SentryEvent) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> - val deserializeEnvelope = - jsonSerializer.deserializeEnvelope(envelopeString.byteInputStream()) - if (deserializeEnvelope == null) { - return@ensureEnvelopeReceived false - } - - val errorItem = - deserializeEnvelope.items.firstOrNull { it.header.type == SentryItemType.Event } - if (errorItem == null) { - return@ensureEnvelopeReceived false - } - - val error = errorItem.getEvent(jsonSerializer) - if (error == null) { - 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 -> - transaction.spans.forEach { span -> - val callbackResult = callback(span) - if (callbackResult) { - return@ensureTransactionReceived true - } - } - false - } - } - - fun reset() { - sentryClient.reset() - } - - fun logObject(obj: Any?) { - obj ?: return - PrintWriter(System.out).use { - jsonSerializer.serialize(obj, it) - } - } - - 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 { - val span = transaction.spans.firstOrNull { span -> span.op == op } - if (span == null) { - println("Unable to find span with op $op in transaction:") - logObject(transaction) - return false - } - - return true - } - - fun doesTransactionContainSpanWithDescription(transaction: SentryTransaction, description: String): Boolean { - val span = transaction.spans.firstOrNull { span -> span.description == description } - if (span == null) { - println("Unable to find span with description $description in transaction:") - logObject(transaction) - return false - } - - return true - } - - fun doesTransactionHaveOp(transaction: SentryTransaction, op: String): Boolean { - val matches = transaction.contexts.trace?.operation == op - if (!matches) { - println("Unable to find transaction with op $op:") - logObject(transaction) - return false - } - - return true - } -} 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 fcc34c8b5b3..6d390ce15fa 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 @@ -6,7 +6,6 @@ plugins { id(Config.BuildPlugins.springDependencyManagement) version Config.BuildPlugins.springDependencyManagementVersion kotlin("jvm") kotlin("plugin.spring") version Config.kotlinVersion - id("com.apollographql.apollo3") version "3.8.2" } group = "io.sentry.sample.spring-boot-webflux-jakarta" @@ -30,6 +29,7 @@ dependencies { implementation(projects.sentryJdbc) implementation(projects.sentryGraphql22) + testImplementation(projects.sentrySystemTestSupport) testImplementation(Config.Libs.springBoot3StarterTest) { exclude(group = "org.junit.vintage", module = "junit-vintage-engine") } @@ -77,13 +77,3 @@ tasks.named("test").configure { excludeTestsMatching("io.sentry.systemtest.*") } } - -apollo { - service("service") { - srcDir("src/test/graphql") - packageName.set("io.sentry.samples.graphql") - outputDirConnection { - connectToKotlinSourceSet("test") - } - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/graphql/greeting.graphql b/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/graphql/greeting.graphql deleted file mode 100644 index 06c866a65fa..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/graphql/greeting.graphql +++ /dev/null @@ -1,3 +0,0 @@ -query GreetingQuery($name: String!) { - greeting(name: $name) -} diff --git a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/graphql/schema.graphqls b/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/graphql/schema.graphqls deleted file mode 100644 index 111e0f2061c..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/graphql/schema.graphqls +++ /dev/null @@ -1,3 +0,0 @@ -type Query { - greeting(name: String! = "Spring"): String! -} diff --git a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt index 769ae399bf0..5681c421a28 100644 --- a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt @@ -19,7 +19,7 @@ class GraphqlGreetingSystemTest { val response = testHelper.graphqlClient.greet("world") testHelper.ensureNoErrors(response) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Query.greeting") } } @@ -32,7 +32,7 @@ class GraphqlGreetingSystemTest { testHelper.ensureErrorReceived { error -> error.message?.message?.startsWith("Unresolved RuntimeException for executionId ") ?: false } - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Query.greeting") } } diff --git a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt index 4708d5609de..f4c3ad40bb1 100644 --- a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt @@ -1,9 +1,7 @@ package io.sentry.systemtest -import io.sentry.samples.spring.boot.jakarta.Person import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals @@ -21,9 +19,9 @@ class PersonSystemTest { fun `get person fails`() { val restClient = testHelper.restClient restClient.getPerson(1L) - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, restClient.lastKnownStatusCode) + assertEquals(500, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionHaveOp(transaction, "http.server") } } @@ -33,12 +31,12 @@ class PersonSystemTest { val restClient = testHelper.restClient val person = Person("firstA", "lastB") val returnedPerson = restClient.createPerson(person) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) assertEquals(person.firstName, returnedPerson!!.firstName) assertEquals(person.lastName, returnedPerson!!.lastName) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionHaveOp(transaction, "http.server") } } diff --git a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt index fe5c8252ed7..33b7cdeb135 100644 --- a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt @@ -2,7 +2,6 @@ package io.sentry.systemtest import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals @@ -20,9 +19,9 @@ class TodoSystemTest { fun `get todo webclient works`() { val restClient = testHelper.restClient restClient.getTodoWebclient(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "http.client") } } diff --git a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt b/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt deleted file mode 100644 index e8301612aed..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt +++ /dev/null @@ -1,28 +0,0 @@ -package io.sentry.systemtest.graphql - -import com.apollographql.apollo3.ApolloClient -import com.apollographql.apollo3.api.ApolloResponse -import com.apollographql.apollo3.api.Mutation -import com.apollographql.apollo3.api.Query -import io.sentry.samples.graphql.GreetingQuery -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? { - return executeQuery(GreetingQuery(name)) - } - - 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-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt b/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt deleted file mode 100644 index 17eea1a0084..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.sentry.systemtest.util - -import org.springframework.http.client.BufferingClientHttpRequestFactory -import org.springframework.web.client.RestTemplate - -open class LoggingInsecureRestClient { - - protected fun restTemplate(): RestTemplate { - return RestTemplate().also { - it.requestFactory = BufferingClientHttpRequestFactory(it.requestFactory) - } - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt b/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt deleted file mode 100644 index 9f77b962945..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt +++ /dev/null @@ -1,65 +0,0 @@ -package io.sentry.systemtest.util - -import io.sentry.samples.spring.boot.jakarta.Person -import io.sentry.samples.spring.boot.jakarta.Todo -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatusCode -import org.springframework.web.client.HttpStatusCodeException - -class RestTestClient(private val backendBaseUrl: String) : LoggingInsecureRestClient() { - var lastKnownStatusCode: HttpStatusCode? = 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - fun createPerson(person: Person): Person? { - return try { - val response = restTemplate().exchange("$backendBaseUrl/person/", HttpMethod.POST, entityWithAuth(person), Person::class.java, person) - lastKnownStatusCode = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - private fun entityWithAuth(request: Any? = null): HttpEntity { - val headers = HttpHeaders().also { - it.setBasicAuth("user", "password") - } - - return HttpEntity(request, headers) - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt b/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt deleted file mode 100644 index 7ef1699f122..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.sentry.systemtest.util - -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod - -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!! - } - - fun reset() { - restTemplate().exchange("$baseUrl/reset", HttpMethod.GET, entityWithAuth(), Any::class.java) - } - - fun getEnvelopes(): EnvelopesReceived { - val response = restTemplate().exchange("$baseUrl/envelopes-received", HttpMethod.GET, entityWithAuth(), EnvelopesReceived::class.java) - return response.body!! - } - - private fun entityWithAuth(request: Any? = null): HttpEntity { - val headers = HttpHeaders() - return HttpEntity(request, headers) - } -} - -class EnvelopeCounts { - val envelopes: Long? = null - - override fun toString(): String { - return "EnvelopeCounts{envelopes=$envelopes}" - } -} - -class EnvelopesReceived { - val envelopes: List? = null - - override fun toString(): String { - return "EnvelopesReceived{envelopes=$envelopes}" - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt b/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt deleted file mode 100644 index 1017d847348..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-webflux-jakarta/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt +++ /dev/null @@ -1,173 +0,0 @@ -package io.sentry.systemtest.util - -import com.apollographql.apollo3.api.ApolloResponse -import com.apollographql.apollo3.api.Operation -import io.sentry.JsonSerializer -import io.sentry.SentryEvent -import io.sentry.SentryItemType -import io.sentry.SentryOptions -import io.sentry.protocol.SentrySpan -import io.sentry.protocol.SentryTransaction -import io.sentry.systemtest.graphql.GraphqlTestClient -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 - - 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(callback: ((String) -> Boolean)) { - Thread.sleep(10000) - val envelopes = sentryClient.getEnvelopes() - assertNotNull(envelopes.envelopes) - envelopes.envelopes.forEach { envelopeString -> - val didMatch = callback(envelopeString) - if (didMatch) { - return - } - } - throw RuntimeException("Unable to find matching envelope received by relay") - } - - fun ensureTransactionReceived(callback: ((SentryTransaction) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> - val deserializeEnvelope = - jsonSerializer.deserializeEnvelope(envelopeString.byteInputStream()) - if (deserializeEnvelope == null) { - return@ensureEnvelopeReceived false - } - - val transactionItem = - deserializeEnvelope.items.firstOrNull { it.header.type == SentryItemType.Transaction } - if (transactionItem == null) { - return@ensureEnvelopeReceived false - } - - val transaction = transactionItem.getTransaction(jsonSerializer) - if (transaction == null) { - return@ensureEnvelopeReceived false - } - - callback(transaction) - } - } - - fun ensureErrorReceived(callback: ((SentryEvent) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> - val deserializeEnvelope = - jsonSerializer.deserializeEnvelope(envelopeString.byteInputStream()) - if (deserializeEnvelope == null) { - return@ensureEnvelopeReceived false - } - - val errorItem = - deserializeEnvelope.items.firstOrNull { it.header.type == SentryItemType.Event } - if (errorItem == null) { - return@ensureEnvelopeReceived false - } - - val error = errorItem.getEvent(jsonSerializer) - if (error == null) { - 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 -> - transaction.spans.forEach { span -> - val callbackResult = callback(span) - if (callbackResult) { - return@ensureTransactionReceived true - } - } - false - } - } - - fun reset() { - sentryClient.reset() - } - - fun logObject(obj: Any?) { - obj ?: return - PrintWriter(System.out).use { - jsonSerializer.serialize(obj, it) - } - } - - 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 { - val span = transaction.spans.firstOrNull { span -> span.op == op } - if (span == null) { - println("Unable to find span with op $op in transaction:") - logObject(transaction) - return false - } - - return true - } - - fun doesTransactionContainSpanWithDescription(transaction: SentryTransaction, description: String): Boolean { - val span = transaction.spans.firstOrNull { span -> span.description == description } - if (span == null) { - println("Unable to find span with description $description in transaction:") - logObject(transaction) - return false - } - - return true - } - - fun doesTransactionHaveOp(transaction: SentryTransaction, op: String): Boolean { - val matches = transaction.contexts.trace?.operation == op - if (!matches) { - println("Unable to find transaction with op $op:") - logObject(transaction) - return false - } - - return true - } -} 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 b39f32514e7..3e50d013107 100644 --- a/sentry-samples/sentry-samples-spring-boot-webflux/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot-webflux/build.gradle.kts @@ -6,7 +6,6 @@ plugins { id(Config.BuildPlugins.springDependencyManagement) version Config.BuildPlugins.springDependencyManagementVersion kotlin("jvm") kotlin("plugin.spring") version Config.kotlinVersion - id("com.apollographql.apollo3") version "3.8.2" } group = "io.sentry.sample.spring-boot" @@ -27,6 +26,8 @@ dependencies { implementation(projects.sentrySpringBootStarter) implementation(projects.sentryLogback) implementation(projects.sentryGraphql) + + testImplementation(projects.sentrySystemTestSupport) testImplementation(Config.Libs.springBootStarterTest) { exclude(group = "org.junit.vintage", module = "junit-vintage-engine") } @@ -75,13 +76,3 @@ tasks.named("test").configure { excludeTestsMatching("io.sentry.systemtest.*") } } - -apollo { - service("service") { - srcDir("src/test/graphql") - packageName.set("io.sentry.samples.graphql") - outputDirConnection { - connectToKotlinSourceSet("test") - } - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/graphql/greeting.graphql b/sentry-samples/sentry-samples-spring-boot-webflux/src/test/graphql/greeting.graphql deleted file mode 100644 index 06c866a65fa..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/graphql/greeting.graphql +++ /dev/null @@ -1,3 +0,0 @@ -query GreetingQuery($name: String!) { - greeting(name: $name) -} diff --git a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/graphql/schema.graphqls b/sentry-samples/sentry-samples-spring-boot-webflux/src/test/graphql/schema.graphqls deleted file mode 100644 index 111e0f2061c..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/graphql/schema.graphqls +++ /dev/null @@ -1,3 +0,0 @@ -type Query { - greeting(name: String! = "Spring"): String! -} diff --git a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt index 769ae399bf0..5681c421a28 100644 --- a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt @@ -19,7 +19,7 @@ class GraphqlGreetingSystemTest { val response = testHelper.graphqlClient.greet("world") testHelper.ensureNoErrors(response) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Query.greeting") } } @@ -32,7 +32,7 @@ class GraphqlGreetingSystemTest { testHelper.ensureErrorReceived { error -> error.message?.message?.startsWith("Unresolved RuntimeException for executionId ") ?: false } - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Query.greeting") } } diff --git a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt index e047431ee5b..f4c3ad40bb1 100644 --- a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt @@ -1,9 +1,7 @@ package io.sentry.systemtest -import io.sentry.samples.spring.boot.Person import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals @@ -21,9 +19,9 @@ class PersonSystemTest { fun `get person fails`() { val restClient = testHelper.restClient restClient.getPerson(1L) - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, restClient.lastKnownStatusCode) + assertEquals(500, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionHaveOp(transaction, "http.server") } } @@ -33,12 +31,12 @@ class PersonSystemTest { val restClient = testHelper.restClient val person = Person("firstA", "lastB") val returnedPerson = restClient.createPerson(person) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) assertEquals(person.firstName, returnedPerson!!.firstName) assertEquals(person.lastName, returnedPerson!!.lastName) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionHaveOp(transaction, "http.server") } } diff --git a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt b/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt index fe5c8252ed7..33b7cdeb135 100644 --- a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt @@ -2,7 +2,6 @@ package io.sentry.systemtest import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals @@ -20,9 +19,9 @@ class TodoSystemTest { fun `get todo webclient works`() { val restClient = testHelper.restClient restClient.getTodoWebclient(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "http.client") } } diff --git a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt b/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt deleted file mode 100644 index e8301612aed..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt +++ /dev/null @@ -1,28 +0,0 @@ -package io.sentry.systemtest.graphql - -import com.apollographql.apollo3.ApolloClient -import com.apollographql.apollo3.api.ApolloResponse -import com.apollographql.apollo3.api.Mutation -import com.apollographql.apollo3.api.Query -import io.sentry.samples.graphql.GreetingQuery -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? { - return executeQuery(GreetingQuery(name)) - } - - 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-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt b/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt deleted file mode 100644 index 0577f0eef21..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt +++ /dev/null @@ -1,32 +0,0 @@ -package io.sentry.systemtest.util - -import org.apache.http.impl.client.HttpClients -import org.springframework.http.client.BufferingClientHttpRequestFactory -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory -import org.springframework.web.client.RestTemplate - -open class LoggingInsecureRestClient { - - protected fun restTemplate(): RestTemplate { - val requestFactory = BufferingClientHttpRequestFactory( - HttpComponentsClientHttpRequestFactory(HttpClients.createDefault()) - ) - return RestTemplate(requestFactory).also { - it.messageConverters.add(0, jacksonConverter()) - } - } - - private fun jacksonConverter(): org.springframework.http.converter.json.MappingJackson2HttpMessageConverter { - val converter = org.springframework.http.converter.json.MappingJackson2HttpMessageConverter() - converter.objectMapper = objectMapper() - return converter - } - - private fun objectMapper(): com.fasterxml.jackson.databind.ObjectMapper { - val builder = org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.json() - val objectMapper: com.fasterxml.jackson.databind.ObjectMapper = builder.createXmlMapper(false).build() - objectMapper.registerModule(com.fasterxml.jackson.datatype.jsr310.JavaTimeModule()) - objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) - return objectMapper - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt b/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt deleted file mode 100644 index f5d5bd7ee38..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt +++ /dev/null @@ -1,65 +0,0 @@ -package io.sentry.systemtest.util - -import io.sentry.samples.spring.boot.Person -import io.sentry.samples.spring.boot.Todo -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus -import org.springframework.web.client.HttpStatusCodeException - -class RestTestClient(private val backendBaseUrl: String) : LoggingInsecureRestClient() { - var lastKnownStatusCode: HttpStatus? = 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - fun createPerson(person: Person): Person? { - return try { - val response = restTemplate().exchange("$backendBaseUrl/person/", HttpMethod.POST, entityWithAuth(person), Person::class.java, person) - lastKnownStatusCode = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - private fun entityWithAuth(request: Any? = null): HttpEntity { - val headers = HttpHeaders().also { - it.setBasicAuth("user", "password") - } - - return HttpEntity(request, headers) - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt b/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt deleted file mode 100644 index 7ef1699f122..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.sentry.systemtest.util - -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod - -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!! - } - - fun reset() { - restTemplate().exchange("$baseUrl/reset", HttpMethod.GET, entityWithAuth(), Any::class.java) - } - - fun getEnvelopes(): EnvelopesReceived { - val response = restTemplate().exchange("$baseUrl/envelopes-received", HttpMethod.GET, entityWithAuth(), EnvelopesReceived::class.java) - return response.body!! - } - - private fun entityWithAuth(request: Any? = null): HttpEntity { - val headers = HttpHeaders() - return HttpEntity(request, headers) - } -} - -class EnvelopeCounts { - val envelopes: Long? = null - - override fun toString(): String { - return "EnvelopeCounts{envelopes=$envelopes}" - } -} - -class EnvelopesReceived { - val envelopes: List? = null - - override fun toString(): String { - return "EnvelopesReceived{envelopes=$envelopes}" - } -} diff --git a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt b/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt deleted file mode 100644 index 1017d847348..00000000000 --- a/sentry-samples/sentry-samples-spring-boot-webflux/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt +++ /dev/null @@ -1,173 +0,0 @@ -package io.sentry.systemtest.util - -import com.apollographql.apollo3.api.ApolloResponse -import com.apollographql.apollo3.api.Operation -import io.sentry.JsonSerializer -import io.sentry.SentryEvent -import io.sentry.SentryItemType -import io.sentry.SentryOptions -import io.sentry.protocol.SentrySpan -import io.sentry.protocol.SentryTransaction -import io.sentry.systemtest.graphql.GraphqlTestClient -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 - - 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(callback: ((String) -> Boolean)) { - Thread.sleep(10000) - val envelopes = sentryClient.getEnvelopes() - assertNotNull(envelopes.envelopes) - envelopes.envelopes.forEach { envelopeString -> - val didMatch = callback(envelopeString) - if (didMatch) { - return - } - } - throw RuntimeException("Unable to find matching envelope received by relay") - } - - fun ensureTransactionReceived(callback: ((SentryTransaction) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> - val deserializeEnvelope = - jsonSerializer.deserializeEnvelope(envelopeString.byteInputStream()) - if (deserializeEnvelope == null) { - return@ensureEnvelopeReceived false - } - - val transactionItem = - deserializeEnvelope.items.firstOrNull { it.header.type == SentryItemType.Transaction } - if (transactionItem == null) { - return@ensureEnvelopeReceived false - } - - val transaction = transactionItem.getTransaction(jsonSerializer) - if (transaction == null) { - return@ensureEnvelopeReceived false - } - - callback(transaction) - } - } - - fun ensureErrorReceived(callback: ((SentryEvent) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> - val deserializeEnvelope = - jsonSerializer.deserializeEnvelope(envelopeString.byteInputStream()) - if (deserializeEnvelope == null) { - return@ensureEnvelopeReceived false - } - - val errorItem = - deserializeEnvelope.items.firstOrNull { it.header.type == SentryItemType.Event } - if (errorItem == null) { - return@ensureEnvelopeReceived false - } - - val error = errorItem.getEvent(jsonSerializer) - if (error == null) { - 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 -> - transaction.spans.forEach { span -> - val callbackResult = callback(span) - if (callbackResult) { - return@ensureTransactionReceived true - } - } - false - } - } - - fun reset() { - sentryClient.reset() - } - - fun logObject(obj: Any?) { - obj ?: return - PrintWriter(System.out).use { - jsonSerializer.serialize(obj, it) - } - } - - 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 { - val span = transaction.spans.firstOrNull { span -> span.op == op } - if (span == null) { - println("Unable to find span with op $op in transaction:") - logObject(transaction) - return false - } - - return true - } - - fun doesTransactionContainSpanWithDescription(transaction: SentryTransaction, description: String): Boolean { - val span = transaction.spans.firstOrNull { span -> span.description == description } - if (span == null) { - println("Unable to find span with description $description in transaction:") - logObject(transaction) - return false - } - - return true - } - - fun doesTransactionHaveOp(transaction: SentryTransaction, op: String): Boolean { - val matches = transaction.contexts.trace?.operation == op - if (!matches) { - println("Unable to find transaction with op $op:") - logObject(transaction) - return false - } - - return true - } -} diff --git a/sentry-samples/sentry-samples-spring-boot/build.gradle.kts b/sentry-samples/sentry-samples-spring-boot/build.gradle.kts index 9c9f090885f..3ffdcc8bef0 100644 --- a/sentry-samples/sentry-samples-spring-boot/build.gradle.kts +++ b/sentry-samples/sentry-samples-spring-boot/build.gradle.kts @@ -6,7 +6,6 @@ plugins { id(Config.BuildPlugins.springDependencyManagement) version Config.BuildPlugins.springDependencyManagementVersion kotlin("jvm") kotlin("plugin.spring") version Config.kotlinVersion - id("com.apollographql.apollo3") version "3.8.2" } group = "io.sentry.sample.spring-boot" @@ -56,6 +55,7 @@ dependencies { // database query tracing implementation(projects.sentryJdbc) runtimeOnly(Config.TestLibs.hsqldb) + testImplementation(projects.sentrySystemTestSupport) testImplementation(Config.Libs.springBootStarterTest) { exclude(group = "org.junit.vintage", module = "junit-vintage-engine") } @@ -97,13 +97,3 @@ tasks.named("test").configure { excludeTestsMatching("io.sentry.systemtest.*") } } - -apollo { - service("service") { - srcDir("src/test/graphql") - packageName.set("io.sentry.samples.graphql") - outputDirConnection { - connectToKotlinSourceSet("test") - } - } -} diff --git a/sentry-samples/sentry-samples-spring-boot/src/test/graphql/greeting.graphql b/sentry-samples/sentry-samples-spring-boot/src/test/graphql/greeting.graphql deleted file mode 100644 index 06c866a65fa..00000000000 --- a/sentry-samples/sentry-samples-spring-boot/src/test/graphql/greeting.graphql +++ /dev/null @@ -1,3 +0,0 @@ -query GreetingQuery($name: String!) { - greeting(name: $name) -} diff --git a/sentry-samples/sentry-samples-spring-boot/src/test/graphql/project.graphql b/sentry-samples/sentry-samples-spring-boot/src/test/graphql/project.graphql deleted file mode 100644 index bff62ed2c2c..00000000000 --- a/sentry-samples/sentry-samples-spring-boot/src/test/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-samples/sentry-samples-spring-boot/src/test/graphql/schema.graphqls b/sentry-samples/sentry-samples-spring-boot/src/test/graphql/schema.graphqls deleted file mode 100644 index d76aca4756a..00000000000 --- a/sentry-samples/sentry-samples-spring-boot/src/test/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-samples/sentry-samples-spring-boot/src/test/graphql/task.graphql b/sentry-samples/sentry-samples-spring-boot/src/test/graphql/task.graphql deleted file mode 100644 index 11ae18574d3..00000000000 --- a/sentry-samples/sentry-samples-spring-boot/src/test/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-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt b/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt index 769ae399bf0..5681c421a28 100644 --- a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/GraphqlGreetingSystemTest.kt @@ -19,7 +19,7 @@ class GraphqlGreetingSystemTest { val response = testHelper.graphqlClient.greet("world") testHelper.ensureNoErrors(response) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Query.greeting") } } @@ -32,7 +32,7 @@ class GraphqlGreetingSystemTest { testHelper.ensureErrorReceived { error -> error.message?.message?.startsWith("Unresolved RuntimeException for executionId ") ?: false } - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Query.greeting") } } diff --git a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt b/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt index 74b196e33b6..bfa38fead33 100644 --- a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/GraphqlProjectSystemTest.kt @@ -23,7 +23,7 @@ class GraphqlProjectSystemTest { testHelper.ensureNoErrors(response) assertEquals("proj-slug", response?.data?.project?.slug) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Query.project") } } @@ -34,7 +34,7 @@ class GraphqlProjectSystemTest { testHelper.ensureNoErrors(response) assertNotNull(response?.data?.addProject) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Mutation.addProject") } } @@ -48,7 +48,7 @@ class GraphqlProjectSystemTest { testHelper.ensureErrorReceived { error -> error.message?.message?.startsWith("Unresolved RuntimeException for executionId ") ?: false } - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Mutation.addProject") } } diff --git a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt b/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt index cf2aebfd090..0f634f309bd 100644 --- a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/GraphqlTaskSystemTest.kt @@ -30,7 +30,7 @@ class GraphqlTaskSystemTest { assertEquals("C3", firstTask.creatorId) assertEquals("C3", firstTask.creator?.id) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithDescription(transaction, "Query.tasks") && testHelper.doesTransactionContainSpanWithDescription(transaction, "Task.assignee") && testHelper.doesTransactionContainSpanWithDescription(transaction, "Task.creator") diff --git a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt b/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt index 96b0860856a..c190b86d6b0 100644 --- a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/PersonSystemTest.kt @@ -1,9 +1,7 @@ package io.sentry.systemtest -import io.sentry.samples.spring.boot.Person import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals @@ -21,9 +19,9 @@ class PersonSystemTest { fun `get person fails`() { val restClient = testHelper.restClient restClient.getPerson(1L) - assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, restClient.lastKnownStatusCode) + assertEquals(500, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionHaveOp(transaction, "http.server") } } @@ -33,12 +31,12 @@ class PersonSystemTest { val restClient = testHelper.restClient val person = Person("firstA", "lastB") val returnedPerson = restClient.createPerson(person) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) assertEquals(person.firstName, returnedPerson!!.firstName) assertEquals(person.lastName, returnedPerson!!.lastName) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "PersonService.create") && testHelper.doesTransactionContainSpanWithOp(transaction, "db.query") } diff --git a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt b/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt index 7a756d98da0..02afc3e0ad6 100644 --- a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt +++ b/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/TodoSystemTest.kt @@ -2,7 +2,6 @@ package io.sentry.systemtest import io.sentry.systemtest.util.TestHelper import org.junit.Before -import org.springframework.http.HttpStatus import kotlin.test.Test import kotlin.test.assertEquals @@ -20,9 +19,9 @@ class TodoSystemTest { fun `get todo works`() { val restClient = testHelper.restClient restClient.getTodo(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "http.client") } } @@ -31,9 +30,9 @@ class TodoSystemTest { fun `get todo webclient works`() { val restClient = testHelper.restClient restClient.getTodoWebclient(1L) - assertEquals(HttpStatus.OK, restClient.lastKnownStatusCode) + assertEquals(200, restClient.lastKnownStatusCode) - testHelper.ensureTransactionReceived { transaction -> + testHelper.ensureTransactionReceived { transaction, envelopeHeader -> testHelper.doesTransactionContainSpanWithOp(transaction, "http.client") } } diff --git a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt b/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt deleted file mode 100644 index 0c11906292b..00000000000 --- a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.sentry.systemtest.graphql - -import com.apollographql.apollo3.ApolloClient -import com.apollographql.apollo3.api.ApolloResponse -import com.apollographql.apollo3.api.Mutation -import com.apollographql.apollo3.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? { - return executeQuery(GreetingQuery(name)) - } - - fun project(slug: String): ApolloResponse? { - return executeQuery(ProjectQuery(slug)) - } - - fun tasksAndAssignees(slug: String): ApolloResponse? { - return executeQuery(TasksAndAssigneesQuery(slug)) - } - - fun addProject(slug: String): ApolloResponse? { - return 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-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt b/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt deleted file mode 100644 index 0577f0eef21..00000000000 --- a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt +++ /dev/null @@ -1,32 +0,0 @@ -package io.sentry.systemtest.util - -import org.apache.http.impl.client.HttpClients -import org.springframework.http.client.BufferingClientHttpRequestFactory -import org.springframework.http.client.HttpComponentsClientHttpRequestFactory -import org.springframework.web.client.RestTemplate - -open class LoggingInsecureRestClient { - - protected fun restTemplate(): RestTemplate { - val requestFactory = BufferingClientHttpRequestFactory( - HttpComponentsClientHttpRequestFactory(HttpClients.createDefault()) - ) - return RestTemplate(requestFactory).also { - it.messageConverters.add(0, jacksonConverter()) - } - } - - private fun jacksonConverter(): org.springframework.http.converter.json.MappingJackson2HttpMessageConverter { - val converter = org.springframework.http.converter.json.MappingJackson2HttpMessageConverter() - converter.objectMapper = objectMapper() - return converter - } - - private fun objectMapper(): com.fasterxml.jackson.databind.ObjectMapper { - val builder = org.springframework.http.converter.json.Jackson2ObjectMapperBuilder.json() - val objectMapper: com.fasterxml.jackson.databind.ObjectMapper = builder.createXmlMapper(false).build() - objectMapper.registerModule(com.fasterxml.jackson.datatype.jsr310.JavaTimeModule()) - objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) - return objectMapper - } -} diff --git a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt b/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt deleted file mode 100644 index f5d5bd7ee38..00000000000 --- a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt +++ /dev/null @@ -1,65 +0,0 @@ -package io.sentry.systemtest.util - -import io.sentry.samples.spring.boot.Person -import io.sentry.samples.spring.boot.Todo -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus -import org.springframework.web.client.HttpStatusCodeException - -class RestTestClient(private val backendBaseUrl: String) : LoggingInsecureRestClient() { - var lastKnownStatusCode: HttpStatus? = 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - fun createPerson(person: Person): Person? { - return try { - val response = restTemplate().exchange("$backendBaseUrl/person/", HttpMethod.POST, entityWithAuth(person), Person::class.java, person) - lastKnownStatusCode = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - 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 = response.statusCode - response.body - } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode - null - } - } - - private fun entityWithAuth(request: Any? = null): HttpEntity { - val headers = HttpHeaders().also { - it.setBasicAuth("user", "password") - } - - return HttpEntity(request, headers) - } -} diff --git a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt b/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt deleted file mode 100644 index 7ef1699f122..00000000000 --- a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt +++ /dev/null @@ -1,43 +0,0 @@ -package io.sentry.systemtest.util - -import org.springframework.http.HttpEntity -import org.springframework.http.HttpHeaders -import org.springframework.http.HttpMethod - -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!! - } - - fun reset() { - restTemplate().exchange("$baseUrl/reset", HttpMethod.GET, entityWithAuth(), Any::class.java) - } - - fun getEnvelopes(): EnvelopesReceived { - val response = restTemplate().exchange("$baseUrl/envelopes-received", HttpMethod.GET, entityWithAuth(), EnvelopesReceived::class.java) - return response.body!! - } - - private fun entityWithAuth(request: Any? = null): HttpEntity { - val headers = HttpHeaders() - return HttpEntity(request, headers) - } -} - -class EnvelopeCounts { - val envelopes: Long? = null - - override fun toString(): String { - return "EnvelopeCounts{envelopes=$envelopes}" - } -} - -class EnvelopesReceived { - val envelopes: List? = null - - override fun toString(): String { - return "EnvelopesReceived{envelopes=$envelopes}" - } -} diff --git a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt b/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt deleted file mode 100644 index 1017d847348..00000000000 --- a/sentry-samples/sentry-samples-spring-boot/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt +++ /dev/null @@ -1,173 +0,0 @@ -package io.sentry.systemtest.util - -import com.apollographql.apollo3.api.ApolloResponse -import com.apollographql.apollo3.api.Operation -import io.sentry.JsonSerializer -import io.sentry.SentryEvent -import io.sentry.SentryItemType -import io.sentry.SentryOptions -import io.sentry.protocol.SentrySpan -import io.sentry.protocol.SentryTransaction -import io.sentry.systemtest.graphql.GraphqlTestClient -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 - - 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(callback: ((String) -> Boolean)) { - Thread.sleep(10000) - val envelopes = sentryClient.getEnvelopes() - assertNotNull(envelopes.envelopes) - envelopes.envelopes.forEach { envelopeString -> - val didMatch = callback(envelopeString) - if (didMatch) { - return - } - } - throw RuntimeException("Unable to find matching envelope received by relay") - } - - fun ensureTransactionReceived(callback: ((SentryTransaction) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> - val deserializeEnvelope = - jsonSerializer.deserializeEnvelope(envelopeString.byteInputStream()) - if (deserializeEnvelope == null) { - return@ensureEnvelopeReceived false - } - - val transactionItem = - deserializeEnvelope.items.firstOrNull { it.header.type == SentryItemType.Transaction } - if (transactionItem == null) { - return@ensureEnvelopeReceived false - } - - val transaction = transactionItem.getTransaction(jsonSerializer) - if (transaction == null) { - return@ensureEnvelopeReceived false - } - - callback(transaction) - } - } - - fun ensureErrorReceived(callback: ((SentryEvent) -> Boolean)) { - ensureEnvelopeReceived { envelopeString -> - val deserializeEnvelope = - jsonSerializer.deserializeEnvelope(envelopeString.byteInputStream()) - if (deserializeEnvelope == null) { - return@ensureEnvelopeReceived false - } - - val errorItem = - deserializeEnvelope.items.firstOrNull { it.header.type == SentryItemType.Event } - if (errorItem == null) { - return@ensureEnvelopeReceived false - } - - val error = errorItem.getEvent(jsonSerializer) - if (error == null) { - 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 -> - transaction.spans.forEach { span -> - val callbackResult = callback(span) - if (callbackResult) { - return@ensureTransactionReceived true - } - } - false - } - } - - fun reset() { - sentryClient.reset() - } - - fun logObject(obj: Any?) { - obj ?: return - PrintWriter(System.out).use { - jsonSerializer.serialize(obj, it) - } - } - - 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 { - val span = transaction.spans.firstOrNull { span -> span.op == op } - if (span == null) { - println("Unable to find span with op $op in transaction:") - logObject(transaction) - return false - } - - return true - } - - fun doesTransactionContainSpanWithDescription(transaction: SentryTransaction, description: String): Boolean { - val span = transaction.spans.firstOrNull { span -> span.description == description } - if (span == null) { - println("Unable to find span with description $description in transaction:") - logObject(transaction) - return false - } - - return true - } - - fun doesTransactionHaveOp(transaction: SentryTransaction, op: String): Boolean { - val matches = transaction.contexts.trace?.operation == op - if (!matches) { - println("Unable to find transaction with op $op:") - logObject(transaction) - return false - } - - return true - } -} diff --git a/sentry-system-test-support/api/sentry-system-test-support.api b/sentry-system-test-support/api/sentry-system-test-support.api new file mode 100644 index 00000000000..f91725edfbf --- /dev/null +++ b/sentry-system-test-support/api/sentry-system-test-support.api @@ -0,0 +1,572 @@ +public final class io/sentry/samples/graphql/AddProjectMutation : com/apollographql/apollo3/api/Mutation { + public static final field Companion Lio/sentry/samples/graphql/AddProjectMutation$Companion; + public static final field OPERATION_ID Ljava/lang/String; + public static final field OPERATION_NAME Ljava/lang/String; + public fun (Ljava/lang/String;)V + public fun adapter ()Lcom/apollographql/apollo3/api/Adapter; + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/sentry/samples/graphql/AddProjectMutation; + public static synthetic fun copy$default (Lio/sentry/samples/graphql/AddProjectMutation;Ljava/lang/String;ILjava/lang/Object;)Lio/sentry/samples/graphql/AddProjectMutation; + public fun document ()Ljava/lang/String; + public fun equals (Ljava/lang/Object;)Z + public final fun getSlug ()Ljava/lang/String; + public fun hashCode ()I + public fun id ()Ljava/lang/String; + public fun name ()Ljava/lang/String; + public fun rootField ()Lcom/apollographql/apollo3/api/CompiledField; + public fun serializeVariables (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)V + public fun toString ()Ljava/lang/String; +} + +public final class io/sentry/samples/graphql/AddProjectMutation$Companion { + public final fun getOPERATION_DOCUMENT ()Ljava/lang/String; +} + +public final class io/sentry/samples/graphql/AddProjectMutation$Data : com/apollographql/apollo3/api/Mutation$Data { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/sentry/samples/graphql/AddProjectMutation$Data; + public static synthetic fun copy$default (Lio/sentry/samples/graphql/AddProjectMutation$Data;Ljava/lang/String;ILjava/lang/Object;)Lio/sentry/samples/graphql/AddProjectMutation$Data; + public fun equals (Ljava/lang/Object;)Z + public final fun getAddProject ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/sentry/samples/graphql/GreetingQuery : com/apollographql/apollo3/api/Query { + public static final field Companion Lio/sentry/samples/graphql/GreetingQuery$Companion; + public static final field OPERATION_ID Ljava/lang/String; + public static final field OPERATION_NAME Ljava/lang/String; + public fun (Ljava/lang/String;)V + public fun adapter ()Lcom/apollographql/apollo3/api/Adapter; + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/sentry/samples/graphql/GreetingQuery; + public static synthetic fun copy$default (Lio/sentry/samples/graphql/GreetingQuery;Ljava/lang/String;ILjava/lang/Object;)Lio/sentry/samples/graphql/GreetingQuery; + public fun document ()Ljava/lang/String; + public fun equals (Ljava/lang/Object;)Z + public final fun getName ()Ljava/lang/String; + public fun hashCode ()I + public fun id ()Ljava/lang/String; + public fun name ()Ljava/lang/String; + public fun rootField ()Lcom/apollographql/apollo3/api/CompiledField; + public fun serializeVariables (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)V + public fun toString ()Ljava/lang/String; +} + +public final class io/sentry/samples/graphql/GreetingQuery$Companion { + public final fun getOPERATION_DOCUMENT ()Ljava/lang/String; +} + +public final class io/sentry/samples/graphql/GreetingQuery$Data : com/apollographql/apollo3/api/Query$Data { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/sentry/samples/graphql/GreetingQuery$Data; + public static synthetic fun copy$default (Lio/sentry/samples/graphql/GreetingQuery$Data;Ljava/lang/String;ILjava/lang/Object;)Lio/sentry/samples/graphql/GreetingQuery$Data; + public fun equals (Ljava/lang/Object;)Z + public final fun getGreeting ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/sentry/samples/graphql/ProjectQuery : com/apollographql/apollo3/api/Query { + public static final field Companion Lio/sentry/samples/graphql/ProjectQuery$Companion; + public static final field OPERATION_ID Ljava/lang/String; + public static final field OPERATION_NAME Ljava/lang/String; + public fun (Ljava/lang/String;)V + public fun adapter ()Lcom/apollographql/apollo3/api/Adapter; + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/sentry/samples/graphql/ProjectQuery; + public static synthetic fun copy$default (Lio/sentry/samples/graphql/ProjectQuery;Ljava/lang/String;ILjava/lang/Object;)Lio/sentry/samples/graphql/ProjectQuery; + public fun document ()Ljava/lang/String; + public fun equals (Ljava/lang/Object;)Z + public final fun getSlug ()Ljava/lang/String; + public fun hashCode ()I + public fun id ()Ljava/lang/String; + public fun name ()Ljava/lang/String; + public fun rootField ()Lcom/apollographql/apollo3/api/CompiledField; + public fun serializeVariables (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)V + public fun toString ()Ljava/lang/String; +} + +public final class io/sentry/samples/graphql/ProjectQuery$Companion { + public final fun getOPERATION_DOCUMENT ()Ljava/lang/String; +} + +public final class io/sentry/samples/graphql/ProjectQuery$Data : com/apollographql/apollo3/api/Query$Data { + public fun (Lio/sentry/samples/graphql/ProjectQuery$Project;)V + public final fun component1 ()Lio/sentry/samples/graphql/ProjectQuery$Project; + public final fun copy (Lio/sentry/samples/graphql/ProjectQuery$Project;)Lio/sentry/samples/graphql/ProjectQuery$Data; + public static synthetic fun copy$default (Lio/sentry/samples/graphql/ProjectQuery$Data;Lio/sentry/samples/graphql/ProjectQuery$Project;ILjava/lang/Object;)Lio/sentry/samples/graphql/ProjectQuery$Data; + public fun equals (Ljava/lang/Object;)Z + public final fun getProject ()Lio/sentry/samples/graphql/ProjectQuery$Project; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/sentry/samples/graphql/ProjectQuery$Project { + public fun (Ljava/lang/String;Ljava/lang/String;Lio/sentry/samples/graphql/type/ProjectStatus;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Lio/sentry/samples/graphql/type/ProjectStatus; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Lio/sentry/samples/graphql/type/ProjectStatus;)Lio/sentry/samples/graphql/ProjectQuery$Project; + public static synthetic fun copy$default (Lio/sentry/samples/graphql/ProjectQuery$Project;Ljava/lang/String;Ljava/lang/String;Lio/sentry/samples/graphql/type/ProjectStatus;ILjava/lang/Object;)Lio/sentry/samples/graphql/ProjectQuery$Project; + public fun equals (Ljava/lang/Object;)Z + public final fun getName ()Ljava/lang/String; + public final fun getSlug ()Ljava/lang/String; + public final fun getStatus ()Lio/sentry/samples/graphql/type/ProjectStatus; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/sentry/samples/graphql/TasksAndAssigneesQuery : com/apollographql/apollo3/api/Query { + public static final field Companion Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Companion; + public static final field OPERATION_ID Ljava/lang/String; + public static final field OPERATION_NAME Ljava/lang/String; + public fun (Ljava/lang/String;)V + public fun adapter ()Lcom/apollographql/apollo3/api/Adapter; + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/sentry/samples/graphql/TasksAndAssigneesQuery; + public static synthetic fun copy$default (Lio/sentry/samples/graphql/TasksAndAssigneesQuery;Ljava/lang/String;ILjava/lang/Object;)Lio/sentry/samples/graphql/TasksAndAssigneesQuery; + public fun document ()Ljava/lang/String; + public fun equals (Ljava/lang/Object;)Z + public final fun getSlug ()Ljava/lang/String; + public fun hashCode ()I + public fun id ()Ljava/lang/String; + public fun name ()Ljava/lang/String; + public fun rootField ()Lcom/apollographql/apollo3/api/CompiledField; + public fun serializeVariables (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)V + public fun toString ()Ljava/lang/String; +} + +public final class io/sentry/samples/graphql/TasksAndAssigneesQuery$Assignee { + public fun (Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Assignee; + public static synthetic fun copy$default (Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Assignee;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Assignee; + public fun equals (Ljava/lang/Object;)Z + public final fun getId ()Ljava/lang/String; + public final fun getName ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/sentry/samples/graphql/TasksAndAssigneesQuery$Companion { + public final fun getOPERATION_DOCUMENT ()Ljava/lang/String; +} + +public final class io/sentry/samples/graphql/TasksAndAssigneesQuery$Creator { + public fun (Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Creator; + public static synthetic fun copy$default (Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Creator;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Creator; + public fun equals (Ljava/lang/Object;)Z + public final fun getId ()Ljava/lang/String; + public final fun getName ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/sentry/samples/graphql/TasksAndAssigneesQuery$Data : com/apollographql/apollo3/api/Query$Data { + public fun (Ljava/util/List;)V + public final fun component1 ()Ljava/util/List; + public final fun copy (Ljava/util/List;)Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Data; + public static synthetic fun copy$default (Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Data;Ljava/util/List;ILjava/lang/Object;)Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Data; + public fun equals (Ljava/lang/Object;)Z + public final fun getTasks ()Ljava/util/List; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/sentry/samples/graphql/TasksAndAssigneesQuery$Task { + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Assignee;Ljava/lang/String;Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Creator;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Assignee; + public final fun component5 ()Ljava/lang/String; + public final fun component6 ()Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Creator; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Assignee;Ljava/lang/String;Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Creator;)Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Task; + public static synthetic fun copy$default (Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Task;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Assignee;Ljava/lang/String;Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Creator;ILjava/lang/Object;)Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Task; + public fun equals (Ljava/lang/Object;)Z + public final fun getAssignee ()Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Assignee; + public final fun getAssigneeId ()Ljava/lang/String; + public final fun getCreator ()Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Creator; + public final fun getCreatorId ()Ljava/lang/String; + public final fun getId ()Ljava/lang/String; + public final fun getName ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/sentry/samples/graphql/adapter/AddProjectMutation_ResponseAdapter { + public static final field INSTANCE Lio/sentry/samples/graphql/adapter/AddProjectMutation_ResponseAdapter; +} + +public final class io/sentry/samples/graphql/adapter/AddProjectMutation_ResponseAdapter$Data : com/apollographql/apollo3/api/Adapter { + public static final field INSTANCE Lio/sentry/samples/graphql/adapter/AddProjectMutation_ResponseAdapter$Data; + public fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lio/sentry/samples/graphql/AddProjectMutation$Data; + public synthetic fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Ljava/lang/Object; + public final fun getRESPONSE_NAMES ()Ljava/util/List; + public fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Lio/sentry/samples/graphql/AddProjectMutation$Data;)V + public synthetic fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/lang/Object;)V +} + +public final class io/sentry/samples/graphql/adapter/AddProjectMutation_VariablesAdapter : com/apollographql/apollo3/api/Adapter { + public static final field INSTANCE Lio/sentry/samples/graphql/adapter/AddProjectMutation_VariablesAdapter; + public fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lio/sentry/samples/graphql/AddProjectMutation; + public synthetic fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Ljava/lang/Object; + public fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Lio/sentry/samples/graphql/AddProjectMutation;)V + public synthetic fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/lang/Object;)V +} + +public final class io/sentry/samples/graphql/adapter/GreetingQuery_ResponseAdapter { + public static final field INSTANCE Lio/sentry/samples/graphql/adapter/GreetingQuery_ResponseAdapter; +} + +public final class io/sentry/samples/graphql/adapter/GreetingQuery_ResponseAdapter$Data : com/apollographql/apollo3/api/Adapter { + public static final field INSTANCE Lio/sentry/samples/graphql/adapter/GreetingQuery_ResponseAdapter$Data; + public fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lio/sentry/samples/graphql/GreetingQuery$Data; + public synthetic fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Ljava/lang/Object; + public final fun getRESPONSE_NAMES ()Ljava/util/List; + public fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Lio/sentry/samples/graphql/GreetingQuery$Data;)V + public synthetic fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/lang/Object;)V +} + +public final class io/sentry/samples/graphql/adapter/GreetingQuery_VariablesAdapter : com/apollographql/apollo3/api/Adapter { + public static final field INSTANCE Lio/sentry/samples/graphql/adapter/GreetingQuery_VariablesAdapter; + public fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lio/sentry/samples/graphql/GreetingQuery; + public synthetic fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Ljava/lang/Object; + public fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Lio/sentry/samples/graphql/GreetingQuery;)V + public synthetic fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/lang/Object;)V +} + +public final class io/sentry/samples/graphql/adapter/ProjectQuery_ResponseAdapter { + public static final field INSTANCE Lio/sentry/samples/graphql/adapter/ProjectQuery_ResponseAdapter; +} + +public final class io/sentry/samples/graphql/adapter/ProjectQuery_ResponseAdapter$Data : com/apollographql/apollo3/api/Adapter { + public static final field INSTANCE Lio/sentry/samples/graphql/adapter/ProjectQuery_ResponseAdapter$Data; + public fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lio/sentry/samples/graphql/ProjectQuery$Data; + public synthetic fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Ljava/lang/Object; + public final fun getRESPONSE_NAMES ()Ljava/util/List; + public fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Lio/sentry/samples/graphql/ProjectQuery$Data;)V + public synthetic fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/lang/Object;)V +} + +public final class io/sentry/samples/graphql/adapter/ProjectQuery_ResponseAdapter$Project : com/apollographql/apollo3/api/Adapter { + public static final field INSTANCE Lio/sentry/samples/graphql/adapter/ProjectQuery_ResponseAdapter$Project; + public fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lio/sentry/samples/graphql/ProjectQuery$Project; + public synthetic fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Ljava/lang/Object; + public final fun getRESPONSE_NAMES ()Ljava/util/List; + public fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Lio/sentry/samples/graphql/ProjectQuery$Project;)V + public synthetic fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/lang/Object;)V +} + +public final class io/sentry/samples/graphql/adapter/ProjectQuery_VariablesAdapter : com/apollographql/apollo3/api/Adapter { + public static final field INSTANCE Lio/sentry/samples/graphql/adapter/ProjectQuery_VariablesAdapter; + public fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lio/sentry/samples/graphql/ProjectQuery; + public synthetic fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Ljava/lang/Object; + public fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Lio/sentry/samples/graphql/ProjectQuery;)V + public synthetic fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/lang/Object;)V +} + +public final class io/sentry/samples/graphql/adapter/TasksAndAssigneesQuery_ResponseAdapter { + public static final field INSTANCE Lio/sentry/samples/graphql/adapter/TasksAndAssigneesQuery_ResponseAdapter; +} + +public final class io/sentry/samples/graphql/adapter/TasksAndAssigneesQuery_ResponseAdapter$Assignee : com/apollographql/apollo3/api/Adapter { + public static final field INSTANCE Lio/sentry/samples/graphql/adapter/TasksAndAssigneesQuery_ResponseAdapter$Assignee; + public fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Assignee; + public synthetic fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Ljava/lang/Object; + public final fun getRESPONSE_NAMES ()Ljava/util/List; + public fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Assignee;)V + public synthetic fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/lang/Object;)V +} + +public final class io/sentry/samples/graphql/adapter/TasksAndAssigneesQuery_ResponseAdapter$Creator : com/apollographql/apollo3/api/Adapter { + public static final field INSTANCE Lio/sentry/samples/graphql/adapter/TasksAndAssigneesQuery_ResponseAdapter$Creator; + public fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Creator; + public synthetic fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Ljava/lang/Object; + public final fun getRESPONSE_NAMES ()Ljava/util/List; + public fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Creator;)V + public synthetic fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/lang/Object;)V +} + +public final class io/sentry/samples/graphql/adapter/TasksAndAssigneesQuery_ResponseAdapter$Data : com/apollographql/apollo3/api/Adapter { + public static final field INSTANCE Lio/sentry/samples/graphql/adapter/TasksAndAssigneesQuery_ResponseAdapter$Data; + public fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Data; + public synthetic fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Ljava/lang/Object; + public final fun getRESPONSE_NAMES ()Ljava/util/List; + public fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Data;)V + public synthetic fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/lang/Object;)V +} + +public final class io/sentry/samples/graphql/adapter/TasksAndAssigneesQuery_ResponseAdapter$Task : com/apollographql/apollo3/api/Adapter { + public static final field INSTANCE Lio/sentry/samples/graphql/adapter/TasksAndAssigneesQuery_ResponseAdapter$Task; + public fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Task; + public synthetic fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Ljava/lang/Object; + public final fun getRESPONSE_NAMES ()Ljava/util/List; + public fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Lio/sentry/samples/graphql/TasksAndAssigneesQuery$Task;)V + public synthetic fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/lang/Object;)V +} + +public final class io/sentry/samples/graphql/adapter/TasksAndAssigneesQuery_VariablesAdapter : com/apollographql/apollo3/api/Adapter { + public static final field INSTANCE Lio/sentry/samples/graphql/adapter/TasksAndAssigneesQuery_VariablesAdapter; + public fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lio/sentry/samples/graphql/TasksAndAssigneesQuery; + public synthetic fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Ljava/lang/Object; + public fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Lio/sentry/samples/graphql/TasksAndAssigneesQuery;)V + public synthetic fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/lang/Object;)V +} + +public final class io/sentry/samples/graphql/selections/AddProjectMutationSelections { + public static final field INSTANCE Lio/sentry/samples/graphql/selections/AddProjectMutationSelections; + public final fun get__root ()Ljava/util/List; +} + +public final class io/sentry/samples/graphql/selections/GreetingQuerySelections { + public static final field INSTANCE Lio/sentry/samples/graphql/selections/GreetingQuerySelections; + public final fun get__root ()Ljava/util/List; +} + +public final class io/sentry/samples/graphql/selections/ProjectQuerySelections { + public static final field INSTANCE Lio/sentry/samples/graphql/selections/ProjectQuerySelections; + public final fun get__root ()Ljava/util/List; +} + +public final class io/sentry/samples/graphql/selections/TasksAndAssigneesQuerySelections { + public static final field INSTANCE Lio/sentry/samples/graphql/selections/TasksAndAssigneesQuerySelections; + public final fun get__root ()Ljava/util/List; +} + +public final class io/sentry/samples/graphql/type/Assignee { + public static final field Companion Lio/sentry/samples/graphql/type/Assignee$Companion; + public fun ()V +} + +public final class io/sentry/samples/graphql/type/Assignee$Companion { + public final fun getType ()Lcom/apollographql/apollo3/api/ObjectType; +} + +public final class io/sentry/samples/graphql/type/Creator { + public static final field Companion Lio/sentry/samples/graphql/type/Creator$Companion; + public fun ()V +} + +public final class io/sentry/samples/graphql/type/Creator$Companion { + public final fun getType ()Lcom/apollographql/apollo3/api/ObjectType; +} + +public final class io/sentry/samples/graphql/type/GraphQLBoolean { + public static final field Companion Lio/sentry/samples/graphql/type/GraphQLBoolean$Companion; + public fun ()V +} + +public final class io/sentry/samples/graphql/type/GraphQLBoolean$Companion { + public final fun getType ()Lcom/apollographql/apollo3/api/CustomScalarType; +} + +public final class io/sentry/samples/graphql/type/GraphQLFloat { + public static final field Companion Lio/sentry/samples/graphql/type/GraphQLFloat$Companion; + public fun ()V +} + +public final class io/sentry/samples/graphql/type/GraphQLFloat$Companion { + public final fun getType ()Lcom/apollographql/apollo3/api/CustomScalarType; +} + +public final class io/sentry/samples/graphql/type/GraphQLID { + public static final field Companion Lio/sentry/samples/graphql/type/GraphQLID$Companion; + public fun ()V +} + +public final class io/sentry/samples/graphql/type/GraphQLID$Companion { + public final fun getType ()Lcom/apollographql/apollo3/api/CustomScalarType; +} + +public final class io/sentry/samples/graphql/type/GraphQLInt { + public static final field Companion Lio/sentry/samples/graphql/type/GraphQLInt$Companion; + public fun ()V +} + +public final class io/sentry/samples/graphql/type/GraphQLInt$Companion { + public final fun getType ()Lcom/apollographql/apollo3/api/CustomScalarType; +} + +public final class io/sentry/samples/graphql/type/GraphQLString { + public static final field Companion Lio/sentry/samples/graphql/type/GraphQLString$Companion; + public fun ()V +} + +public final class io/sentry/samples/graphql/type/GraphQLString$Companion { + public final fun getType ()Lcom/apollographql/apollo3/api/CustomScalarType; +} + +public final class io/sentry/samples/graphql/type/Mutation { + public static final field Companion Lio/sentry/samples/graphql/type/Mutation$Companion; + public fun ()V +} + +public final class io/sentry/samples/graphql/type/Mutation$Companion { + public final fun getType ()Lcom/apollographql/apollo3/api/ObjectType; +} + +public final class io/sentry/samples/graphql/type/Project { + public static final field Companion Lio/sentry/samples/graphql/type/Project$Companion; + public fun ()V +} + +public final class io/sentry/samples/graphql/type/Project$Companion { + public final fun getType ()Lcom/apollographql/apollo3/api/ObjectType; +} + +public final class io/sentry/samples/graphql/type/ProjectStatus : java/lang/Enum { + public static final field ACTIVE Lio/sentry/samples/graphql/type/ProjectStatus; + public static final field ATTIC Lio/sentry/samples/graphql/type/ProjectStatus; + public static final field COMMUNITY Lio/sentry/samples/graphql/type/ProjectStatus; + public static final field Companion Lio/sentry/samples/graphql/type/ProjectStatus$Companion; + public static final field EOL Lio/sentry/samples/graphql/type/ProjectStatus; + public static final field INCUBATING Lio/sentry/samples/graphql/type/ProjectStatus; + public static final field UNKNOWN__ Lio/sentry/samples/graphql/type/ProjectStatus; + public static fun getEntries ()Lkotlin/enums/EnumEntries; + public final fun getRawValue ()Ljava/lang/String; + public static fun valueOf (Ljava/lang/String;)Lio/sentry/samples/graphql/type/ProjectStatus; + public static fun values ()[Lio/sentry/samples/graphql/type/ProjectStatus; +} + +public final class io/sentry/samples/graphql/type/ProjectStatus$Companion { + public final fun getType ()Lcom/apollographql/apollo3/api/EnumType; + public final fun knownValues ()[Lio/sentry/samples/graphql/type/ProjectStatus; + public final fun safeValueOf (Ljava/lang/String;)Lio/sentry/samples/graphql/type/ProjectStatus; +} + +public final class io/sentry/samples/graphql/type/Query { + public static final field Companion Lio/sentry/samples/graphql/type/Query$Companion; + public fun ()V +} + +public final class io/sentry/samples/graphql/type/Query$Companion { + public final fun getType ()Lcom/apollographql/apollo3/api/ObjectType; +} + +public final class io/sentry/samples/graphql/type/Task { + public static final field Companion Lio/sentry/samples/graphql/type/Task$Companion; + public fun ()V +} + +public final class io/sentry/samples/graphql/type/Task$Companion { + public final fun getType ()Lcom/apollographql/apollo3/api/ObjectType; +} + +public final class io/sentry/samples/graphql/type/adapter/ProjectStatus_ResponseAdapter : com/apollographql/apollo3/api/Adapter { + public static final field INSTANCE Lio/sentry/samples/graphql/type/adapter/ProjectStatus_ResponseAdapter; + public fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Lio/sentry/samples/graphql/type/ProjectStatus; + public synthetic fun fromJson (Lcom/apollographql/apollo3/api/json/JsonReader;Lcom/apollographql/apollo3/api/CustomScalarAdapters;)Ljava/lang/Object; + public fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Lio/sentry/samples/graphql/type/ProjectStatus;)V + public synthetic fun toJson (Lcom/apollographql/apollo3/api/json/JsonWriter;Lcom/apollographql/apollo3/api/CustomScalarAdapters;Ljava/lang/Object;)V +} + +public final class io/sentry/systemtest/Person { + public fun (Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lio/sentry/systemtest/Person; + public static synthetic fun copy$default (Lio/sentry/systemtest/Person;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/sentry/systemtest/Person; + public fun equals (Ljava/lang/Object;)Z + public final fun getFirstName ()Ljava/lang/String; + public final fun getLastName ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/sentry/systemtest/Todo { + public fun (JLjava/lang/String;Z)V + public final fun component1 ()J + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Z + 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 getId ()J + public final fun getTitle ()Ljava/lang/String; + public fun hashCode ()I + public final fun isCompleted ()Z + public fun toString ()Ljava/lang/String; +} + +public final class io/sentry/systemtest/graphql/GraphqlTestClient { + public fun (Ljava/lang/String;)V + public final fun addProject (Ljava/lang/String;)Lcom/apollographql/apollo3/api/ApolloResponse; + public final fun getApollo ()Lcom/apollographql/apollo3/ApolloClient; + public final fun greet (Ljava/lang/String;)Lcom/apollographql/apollo3/api/ApolloResponse; + public final fun project (Ljava/lang/String;)Lcom/apollographql/apollo3/api/ApolloResponse; + public final fun tasksAndAssignees (Ljava/lang/String;)Lcom/apollographql/apollo3/api/ApolloResponse; +} + +public final class io/sentry/systemtest/util/EnvelopeCounts { + public fun ()V + public final fun getEnvelopes ()Ljava/lang/Long; + public fun toString ()Ljava/lang/String; +} + +public final class io/sentry/systemtest/util/EnvelopesReceived { + public fun ()V + public final fun getEnvelopes ()Ljava/util/List; + public fun toString ()Ljava/lang/String; +} + +public class io/sentry/systemtest/util/LoggingInsecureRestClient { + public fun ()V + protected final fun restTemplate ()Lorg/springframework/web/client/RestTemplate; +} + +public final class io/sentry/systemtest/util/RestTestClient : io/sentry/systemtest/util/LoggingInsecureRestClient { + public fun (Ljava/lang/String;)V + public final fun createPerson (Lio/sentry/systemtest/Person;Ljava/util/Map;)Lio/sentry/systemtest/Person; + 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 { + public fun (Ljava/lang/String;)V + public final fun getEnvelopeCount ()Lio/sentry/systemtest/util/EnvelopeCounts; + public final fun getEnvelopes ()Lio/sentry/systemtest/util/EnvelopesReceived; + public final fun reset ()V +} + +public final class io/sentry/systemtest/util/TestHelper { + public fun (Ljava/lang/String;)V + public final fun doesTransactionContainSpanWithDescription (Lio/sentry/protocol/SentryTransaction;Ljava/lang/String;)Z + public final fun doesTransactionContainSpanWithOp (Lio/sentry/protocol/SentryTransaction;Ljava/lang/String;)Z + public final fun doesTransactionHaveOp (Lio/sentry/protocol/SentryTransaction;Ljava/lang/String;)Z + public final fun doesTransactionHaveTraceId (Lio/sentry/protocol/SentryTransaction;Ljava/lang/String;)Z + public final fun ensureEnvelopeCountIncreased ()V + public final fun ensureEnvelopeReceived (Lkotlin/jvm/functions/Function1;)V + public final fun ensureErrorCount (Lcom/apollographql/apollo3/api/ApolloResponse;I)V + public final fun ensureErrorReceived (Lkotlin/jvm/functions/Function1;)V + public final fun ensureNoEnvelopeReceived (Lkotlin/jvm/functions/Function1;)V + public final fun ensureNoErrors (Lcom/apollographql/apollo3/api/ApolloResponse;)V + public final fun ensureNoTransactionReceived (Lkotlin/jvm/functions/Function2;)V + public final fun ensureTransactionReceived (Lkotlin/jvm/functions/Function2;)V + public final fun ensureTransactionWithSpanReceived (Lkotlin/jvm/functions/Function1;)V + public final fun getEnvelopeCounts ()Lio/sentry/systemtest/util/EnvelopeCounts; + public final fun getGraphqlClient ()Lio/sentry/systemtest/graphql/GraphqlTestClient; + public final fun getJsonSerializer ()Lio/sentry/JsonSerializer; + public final fun getRestClient ()Lio/sentry/systemtest/util/RestTestClient; + public final fun getSentryClient ()Lio/sentry/systemtest/util/SentryMockServerClient; + public final fun logObject (Ljava/lang/Object;)V + public final fun reset ()V + public final fun setEnvelopeCounts (Lio/sentry/systemtest/util/EnvelopeCounts;)V + public final fun snapshotEnvelopeCount ()V +} + diff --git a/sentry-system-test-support/build.gradle.kts b/sentry-system-test-support/build.gradle.kts new file mode 100644 index 00000000000..b5392694a49 --- /dev/null +++ b/sentry-system-test-support/build.gradle.kts @@ -0,0 +1,54 @@ +plugins { + `java-library` + kotlin("jvm") + jacoco + id(Config.QualityPlugins.errorProne) + id(Config.QualityPlugins.gradleVersions) + id("com.apollographql.apollo3") version "3.8.2" +} + +configure { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + +tasks.withType().configureEach { + kotlinOptions.jvmTarget = JavaVersion.VERSION_17.toString() +} + +dependencies { + api(projects.sentry) + compileOnly(Config.Libs.springBoot3StarterTest) { + exclude(group = "org.junit.vintage", module = "junit-vintage-engine") + } + compileOnly(Config.Libs.springBoot3StarterWeb) + api(Config.Libs.apolloKotlin) + implementation(Config.Libs.jacksonKotlin) + api(projects.sentryTestSupport) + + compileOnly(Config.CompileOnly.nopen) + errorprone(Config.CompileOnly.nopenChecker) + errorprone(Config.CompileOnly.errorprone) + compileOnly(Config.CompileOnly.jetbrainsAnnotations) + + // tests + implementation(kotlin(Config.kotlinStdLib)) + implementation(Config.TestLibs.kotlinTestJunit) + implementation(Config.TestLibs.mockitoKotlin) +} + +configure { + test { + java.srcDir("src/test/java") + } +} + +apollo { + service("service") { + srcDir("src/main/graphql") + packageName.set("io.sentry.samples.graphql") + outputDirConnection { + connectToKotlinSourceSet("main") + } + } +} diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/graphql/greeting.graphql b/sentry-system-test-support/src/main/graphql/greeting.graphql similarity index 100% rename from sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/graphql/greeting.graphql rename to sentry-system-test-support/src/main/graphql/greeting.graphql diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/graphql/project.graphql b/sentry-system-test-support/src/main/graphql/project.graphql similarity index 100% rename from sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/graphql/project.graphql rename to sentry-system-test-support/src/main/graphql/project.graphql diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/graphql/schema.graphqls b/sentry-system-test-support/src/main/graphql/schema.graphqls similarity index 100% rename from sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/graphql/schema.graphqls rename to sentry-system-test-support/src/main/graphql/schema.graphqls diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/graphql/task.graphql b/sentry-system-test-support/src/main/graphql/task.graphql similarity index 100% rename from sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/graphql/task.graphql rename to sentry-system-test-support/src/main/graphql/task.graphql 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 new file mode 100644 index 00000000000..fb7721bd942 --- /dev/null +++ b/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/ResponseTypes.kt @@ -0,0 +1,10 @@ +package io.sentry.systemtest + +data class Todo(val id: Long, val title: String, val isCompleted: Boolean) + +data class Person(val firstName: String, val lastName: String) { + + override fun toString(): String { + return "Person{firstName='$firstName', lastName='$lastName'}" + } +} diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt b/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt similarity index 100% rename from sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt rename to sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/graphql/GraphqlTestClient.kt diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt b/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt similarity index 100% rename from sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt rename to sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/LoggingInsecureRestClient.kt diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt b/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/RestTestClient.kt similarity index 51% rename from sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt rename to sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/RestTestClient.kt index f50632f381c..7a8792a13bf 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/RestTestClient.kt +++ b/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/RestTestClient.kt @@ -1,75 +1,67 @@ package io.sentry.systemtest.util -import io.sentry.samples.spring.boot.jakarta.Person -import io.sentry.samples.spring.boot.jakarta.Todo +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.HttpStatusCode +import org.springframework.http.ResponseEntity import org.springframework.web.client.HttpStatusCodeException class RestTestClient(private val backendBaseUrl: String) : LoggingInsecureRestClient() { - var lastKnownStatusCode: HttpStatusCode? = null + 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 = response.statusCode + lastKnownStatusCode = statusCode(response) response.body } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode + lastKnownStatusCode = statusCode(e) null } } - fun createPerson(person: Person): Person? { + fun createPerson(person: Person, extraHeaders: Map? = null): Person? { return try { - val response = restTemplate().exchange("$backendBaseUrl/person/", HttpMethod.POST, entityWithAuth(person), Person::class.java, person) - lastKnownStatusCode = response.statusCode + val response = restTemplate().exchange("$backendBaseUrl/person/", HttpMethod.POST, entityWithAuth(person, extraHeaders), Person::class.java, person) + lastKnownStatusCode = statusCode(response) response.body } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode + lastKnownStatusCode = statusCode(e) null } } - fun getPersonDistributedTracing(id: Long, sentryTraceHeader: String? = null, baggageHeader: String? = null): Person? { + fun getPersonDistributedTracing(id: Long, extraHeaders: Map? = null): Person? { return try { - val response = restTemplate().exchange("$backendBaseUrl/tracing/{id}", HttpMethod.GET, entityWithAuth(headerCallback = tracingHeaders(sentryTraceHeader, baggageHeader)), Person::class.java, mapOf("id" to id)) - lastKnownStatusCode = response.statusCode + 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 = e.statusCode + lastKnownStatusCode = statusCode(e) null } } - fun createPersonDistributedTracing(person: Person, sentryTraceHeader: String? = null, baggageHeader: String? = null): Person? { + fun createPersonDistributedTracing(person: Person, extraHeaders: Map? = null): Person? { return try { - val response = restTemplate().exchange("$backendBaseUrl/tracing/", HttpMethod.POST, entityWithAuth(person, tracingHeaders(sentryTraceHeader, baggageHeader)), Person::class.java, person) - lastKnownStatusCode = response.statusCode + val response = restTemplate().exchange("$backendBaseUrl/tracing/", HttpMethod.POST, entityWithAuth(person, extraHeaders), Person::class.java, person) + lastKnownStatusCode = statusCode(response) response.body } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode + lastKnownStatusCode = statusCode(e) null } } - private fun tracingHeaders(sentryTraceHeader: String?, baggageHeader: String?): (HttpHeaders) -> HttpHeaders { - return { httpHeaders -> - sentryTraceHeader?.let { httpHeaders.set("sentry-trace", it) } - baggageHeader?.let { httpHeaders.set("baggage", it) } - httpHeaders - } - } - 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 = response.statusCode + lastKnownStatusCode = statusCode(response) response.body } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode + lastKnownStatusCode = statusCode(e) null } } @@ -77,10 +69,10 @@ class RestTestClient(private val backendBaseUrl: String) : LoggingInsecureRestCl 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 = response.statusCode + lastKnownStatusCode = statusCode(response) response.body } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode + lastKnownStatusCode = statusCode(e) null } } @@ -88,21 +80,34 @@ class RestTestClient(private val backendBaseUrl: String) : LoggingInsecureRestCl 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 = response.statusCode + lastKnownStatusCode = statusCode(response) response.body } catch (e: HttpStatusCodeException) { - lastKnownStatusCode = e.statusCode + lastKnownStatusCode = statusCode(e) null } } - private fun entityWithAuth(request: Any? = null, headerCallback: ((HttpHeaders) -> HttpHeaders)? = null): HttpEntity { + 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) } + + return HttpEntity(request, headers) + } + + private fun statusCode(o: Any): Int? { + val statusCodeValue = (o as? ResponseEntity)?.statusCodeValue + if (statusCodeValue != null) { + return statusCodeValue + } - val modifiedHeaders = headerCallback?.invoke(headers) ?: headers + val errorStatusCodeValue = (o as? HttpStatusCodeException)?.rawStatusCode + if (errorStatusCodeValue != null) { + return errorStatusCodeValue + } - return HttpEntity(request, modifiedHeaders) + return null } } diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt b/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt similarity index 100% rename from sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt rename to sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/SentryMockServerClient.kt diff --git a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt b/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/TestHelper.kt similarity index 95% rename from sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt rename to sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/TestHelper.kt index 14bac5cd0ea..bbd42fd7415 100644 --- a/sentry-samples/sentry-samples-spring-boot-jakarta-opentelemetry-noagent/src/test/kotlin/io/sentry/systemtest/util/TestHelper.kt +++ b/sentry-system-test-support/src/main/kotlin/io/sentry/systemtest/util/TestHelper.kt @@ -200,4 +200,15 @@ class TestHelper(backendUrl: String) { return true } + + fun doesTransactionHaveOp(transaction: SentryTransaction, op: String): Boolean { + val matches = transaction.contexts.trace?.operation == op + if (!matches) { + println("Unable to find transaction with op $op:") + logObject(transaction) + return false + } + + return true + } } diff --git a/settings.gradle.kts b/settings.gradle.kts index e5fdc079f79..4c642f1abd6 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -26,6 +26,7 @@ include( "sentry-apollo", "sentry-apollo-3", "sentry-apollo-4", + "sentry-system-test-support", "sentry-test-support", "sentry-log4j2", "sentry-logback",