Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Apollo Execution #6138

Merged
merged 3 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion gradle/libraries.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ android-sdkversion-target = "30"
androidx-sqlite = "2.3.1"
# This is used by the gradle integration tests to get the artifacts locally
apollo = "4.0.1-SNAPSHOT"
apollo-execution = "0.0.2"
apollo-execution = "0.0.3"
apollo-normalizedcache-incubating-snapshot = "0.0.3-SNAPSHOT"
# Used by the apollo-tooling project which uses a published version of Apollo
apollo-published = "4.0.0-rc.1"
Expand Down Expand Up @@ -79,6 +79,7 @@ apollo-compiler = { group = "com.apollographql.apollo", name = "apollo-compiler"
apollo-ast = { group = "com.apollographql.apollo", name = "apollo-ast", version.ref = "apollo" }
apollo-execution = { group = "com.apollographql.execution", name = "apollo-execution-runtime", version.ref = "apollo-execution" }
apollo-execution-ktor = { group = "com.apollographql.execution", name = "apollo-execution-ktor", version.ref = "apollo-execution" }
apollo-execution-http4k = { group = "com.apollographql.execution", name = "apollo-execution-http4k", version.ref = "apollo-execution" }
apollo-execution-processor = { group = "com.apollographql.execution", name = "apollo-execution-processor", version.ref = "apollo-execution" }
apollo-execution-gradle-plugin = { group = "com.apollographql.execution", name = "apollo-execution-gradle-plugin", version.ref = "apollo-execution" }
# Used by the apollo-tooling project which uses a published version of Apollo
Expand Down
10 changes: 8 additions & 2 deletions libraries/apollo-debug-server/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,13 @@ tasks.configureEach {

apolloExecution {
service("apolloDebugServer") {
packageName = "com.apollographql.apollo.debugserver.internal.graphql"
schemaPath.set("graphql/schema.graphqls")
packageName.set("com.apollographql.apollo.debugserver.internal.graphql")
}
}

/**
* apolloCheckSchema is registered as a dependent of build but the ci doesn't call the "build" task directly
*/
tasks.named("jvmTest") {
finalizedBy("apolloCheckSchema")
}
4 changes: 2 additions & 2 deletions libraries/apollo-debug-server/graphql/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ schema {
query: Query
}

scalar Fields

"""
The root query
"""
Expand Down Expand Up @@ -43,3 +41,5 @@ type Record {

sizeInBytes: Int!
}

scalar Fields
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,19 @@ import com.apollographql.apollo.cache.normalized.apolloStore
import com.apollographql.execution.Coercing
import com.apollographql.execution.ExecutableSchema
import com.apollographql.execution.StringCoercing
import com.apollographql.execution.annotation.GraphQLCoercing
import com.apollographql.execution.annotation.GraphQLName
import com.apollographql.execution.annotation.GraphQLQueryRoot
import com.apollographql.execution.annotation.GraphQLQuery
import com.apollographql.execution.annotation.GraphQLScalar
import com.apollographql.execution.internal.ExternalValue
import com.apollographql.execution.internal.InternalValue
import com.apollographql.execution.parsePostGraphQLRequest
import com.apollographql.execution.parseGraphQLRequest
import okio.Buffer
import java.util.concurrent.atomic.AtomicReference
import kotlin.reflect.KClass

@GraphQLScalar
@GraphQLScalar(StringCoercing::class)
internal typealias ID = String

@GraphQLCoercing
internal object IDCoercing: Coercing<ID> by StringCoercing

internal class GraphQL(
private val apolloClients: AtomicReference<Map<ApolloClient, String>>,
) {
Expand All @@ -37,7 +33,7 @@ internal class GraphQL(
}

fun executeGraphQL(jsonBody: String): String {
val graphQLRequestResult = Buffer().writeUtf8(jsonBody).parsePostGraphQLRequest()
val graphQLRequestResult = Buffer().writeUtf8(jsonBody).parseGraphQLRequest()
if (!graphQLRequestResult.isSuccess) {
return graphQLRequestResult.exceptionOrNull()!!.message!!
}
Expand All @@ -53,7 +49,7 @@ internal class GraphQL(
/**
* The root query
*/
@GraphQLQueryRoot
@GraphQLQuery
internal class Query(private val apolloClients: AtomicReference<Map<ApolloClient, String>>) {
private fun graphQLApolloClients() =
apolloClients.get().map { (apolloClient, apolloClientId) ->
Expand Down Expand Up @@ -111,7 +107,7 @@ internal class NormalizedCache(
fun records(): List<GraphQLRecord> = records.map { GraphQLRecord(it.value) }
}

@GraphQLScalar
@GraphQLScalar(FieldsCoercing::class)
typealias Fields = Map<String, Any?>

@GraphQLName("Record")
Expand All @@ -125,8 +121,7 @@ internal class GraphQLRecord(
fun sizeInBytes(): Int = record.sizeInBytes
}

@GraphQLCoercing
internal class FieldsCoercing : Coercing<Fields> {
internal object FieldsCoercing : Coercing<Fields> {
// Taken from JsonRecordSerializer
@Suppress("UNCHECKED_CAST")
private fun InternalValue.toExternal(): ExternalValue {
Expand Down
2 changes: 1 addition & 1 deletion libraries/apollo-gradle-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ dependencies {
testImplementation(libs.okhttp.tls)

testImplementation(libs.apollo.execution)
testImplementation(libs.apollo.execution.http4k)

testImplementation(platform(libs.http4k.bom.get()))
testImplementation(libs.http4k.core)
Expand Down Expand Up @@ -85,7 +86,6 @@ if (relocateJar) {
apiDependencies.remove(it)
}


configurations.named("compileOnly").configure {
extendsFrom(shadeConfiguration)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,17 @@
package com.apollographql.apollo.gradle.test
package test


import com.apollographql.apollo.api.ExecutionContext
import com.apollographql.execution.ExecutableSchema
import com.apollographql.execution.parsePostGraphQLRequest
import com.apollographql.execution.http4k.apolloHandler
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okhttp3.tls.HandshakeCertificates
import okhttp3.tls.HeldCertificate
import okio.Buffer
import okio.buffer
import okio.source
import org.gradle.testkit.runner.TaskOutcome
import org.http4k.core.HttpHandler
import org.http4k.core.Method
import org.http4k.core.Request
import org.http4k.core.Response
import org.http4k.core.Status
import org.http4k.routing.bind
import org.http4k.routing.routes
import org.http4k.server.Jetty
import org.http4k.server.asServer
import org.junit.Assert.assertEquals
import org.junit.Assert
import org.junit.Test
import util.TestUtils
import util.TestUtils.withSimpleProject
import util.TestUtils.withTestProject
import java.io.File

class DownloadSchemaTests {
Expand Down Expand Up @@ -158,44 +144,44 @@ class DownloadSchemaTests {

@Test
fun `schema is downloaded correctly`() {
withSimpleProject(apolloConfiguration = apolloConfiguration) { dir ->
TestUtils.withSimpleProject(apolloConfiguration = apolloConfiguration) { dir ->
mockServer.enqueue(MockResponse().setBody(preIntrospectionResponse))
mockServer.enqueue(MockResponse().setBody(schemaString1))

TestUtils.executeTask("downloadMockApolloSchemaFromIntrospection", dir)

assertEquals(schemaString1, File(dir, "src/main/graphql/com/example/schema.json").readText())
Assert.assertEquals(schemaString1, File(dir, "src/main/graphql/com/example/schema.json").readText())
}
}


@Test
fun `download schema is never up-to-date`() {

withSimpleProject(apolloConfiguration = apolloConfiguration) { dir ->
TestUtils.withSimpleProject(apolloConfiguration = apolloConfiguration) { dir ->
val preIntrospectionMockResponse = MockResponse().setBody(preIntrospectionResponse)
val schemaMockResponse = MockResponse().setBody(schemaString1)
mockServer.enqueue(preIntrospectionMockResponse)
mockServer.enqueue(schemaMockResponse)

var result = TestUtils.executeTask("downloadMockApolloSchemaFromIntrospection", dir)
assertEquals(TaskOutcome.SUCCESS, result.task(":downloadMockApolloSchemaFromIntrospection")?.outcome)
Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":downloadMockApolloSchemaFromIntrospection")?.outcome)

mockServer.enqueue(preIntrospectionMockResponse)
mockServer.enqueue(schemaMockResponse)

// Since the task does not declare any output, it should never be up-to-date
result = TestUtils.executeTask("downloadMockApolloSchemaFromIntrospection", dir)
assertEquals(TaskOutcome.SUCCESS, result.task(":downloadMockApolloSchemaFromIntrospection")?.outcome)
Assert.assertEquals(TaskOutcome.SUCCESS, result.task(":downloadMockApolloSchemaFromIntrospection")?.outcome)

assertEquals(schemaString1, File(dir, "src/main/graphql/com/example/schema.json").readText())
Assert.assertEquals(schemaString1, File(dir, "src/main/graphql/com/example/schema.json").readText())
}
}

@Test
fun `download schema is never cached`() {

withSimpleProject(apolloConfiguration = apolloConfiguration) { dir ->
TestUtils.withSimpleProject(apolloConfiguration = apolloConfiguration) { dir ->
val buildCacheDir = File(dir, "buildCache")

File(dir, "settings.gradle").appendText("""
Expand All @@ -206,7 +192,8 @@ class DownloadSchemaTests {
directory '${buildCacheDir.absolutePath}'
}
}
""".trimIndent())
""".trimIndent()
)

val schemaFile = File(dir, "src/main/graphql/com/example/schema.json")

Expand All @@ -215,20 +202,20 @@ class DownloadSchemaTests {
mockServer.enqueue(MockResponse().setBody(schemaString1))

TestUtils.executeTask("downloadMockApolloSchemaFromIntrospection", dir, "--build-cache")
assertEquals(schemaString1, schemaFile.readText())
Assert.assertEquals(schemaString1, schemaFile.readText())

mockServer.enqueue(preIntrospectionMockResponse)
mockServer.enqueue(MockResponse().setBody(schemaString2))

TestUtils.executeTask("downloadMockApolloSchemaFromIntrospection", dir, "--build-cache")
assertEquals(schemaString2, schemaFile.readText())
Assert.assertEquals(schemaString2, schemaFile.readText())
}
}

@Test
fun `manually downloading a schema is working`() {

withSimpleProject(apolloConfiguration = "") { dir ->
TestUtils.withSimpleProject(apolloConfiguration = "") { dir ->
mockServer.enqueue(MockResponse().setBody(preIntrospectionResponse))
mockServer.enqueue(MockResponse().setBody(schemaString1))

Expand All @@ -240,15 +227,16 @@ class DownloadSchemaTests {

TestUtils.executeGradle(dir, "downloadApolloSchema",
"--schema=${schema.absolutePath}",
"--endpoint=${mockServer.url("/")}")
"--endpoint=${mockServer.url("/")}"
)

assertEquals(schemaString1, schema.readText())
Assert.assertEquals(schemaString1, schema.readText())
}
}

@Test
fun `manually downloading a schema from self signed endpoint is working`() {
withSimpleProject(apolloConfiguration = "") { dir ->
TestUtils.withSimpleProject(apolloConfiguration = "") { dir ->
mockServer.enqueue(MockResponse().setBody(preIntrospectionResponse))
mockServer.enqueue(MockResponse().setBody(schemaString1))

Expand All @@ -261,9 +249,10 @@ class DownloadSchemaTests {
TestUtils.executeGradle(dir, "downloadApolloSchema",
"--schema=${schema.absolutePath}",
"--endpoint=${mockServer.url("/")}",
"--insecure")
"--insecure"
)

assertEquals(schemaString1, schema.readText())
Assert.assertEquals(schemaString1, schema.readText())
}
}

Expand All @@ -273,40 +262,16 @@ class DownloadSchemaTests {
.schema("type Query {foo: Int}")
.build()

val server = routes("/graphql" bind Method.POST to GraphQLHttpHandler(executableSchema, ExecutionContext.Empty))
val server = apolloHandler(executableSchema)
.asServer(Jetty(8001))
.start()

val buildResult = withTestProject("downloadIntrospection") {dir ->
val buildResult = TestUtils.withTestProject("downloadIntrospection") { dir ->
TestUtils.executeGradle(dir, "downloadServiceApolloSchemaFromIntrospection")
}

assertEquals(TaskOutcome.SUCCESS, buildResult.task(":downloadServiceApolloSchemaFromIntrospection")?.outcome)
Assert.assertEquals(TaskOutcome.SUCCESS, buildResult.task(":downloadServiceApolloSchemaFromIntrospection")?.outcome)

server.stop()
}

class GraphQLHttpHandler(private val executableSchema: ExecutableSchema, private val executionContext: ExecutionContext) : HttpHandler {
override fun invoke(request: Request): Response {

val graphQLRequestResult = when (request.method) {
org.http4k.core.Method.POST -> request.body.stream.source().buffer().use { it.parsePostGraphQLRequest() }
else -> error("")
}

if (graphQLRequestResult.isFailure) {
return Response(Status.BAD_REQUEST).body(graphQLRequestResult.exceptionOrNull()?.message ?: "")
}

val response = executableSchema.execute(graphQLRequestResult.getOrThrow(), executionContext)

val buffer = Buffer()
response.serialize(buffer)
val responseText = buffer.readUtf8()

return Response(Status.OK)
.header("content-type", "application/json")
.body(responseText)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ apollo {
service("service") {
packageName.set("com.example")
introspection {
endpointUrl.set("http://localhost:8001/graphql")
endpointUrl.set("http://localhost:8001/")
schemaFile.set(file("schema.graphqls"))
}
}
Expand Down
12 changes: 6 additions & 6 deletions tests/sample-server/graphql/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,29 @@ type QueryRoot {
}

type MutationRoot {
closeAllWebSockets: ID!
closeAllWebSockets: String!
}

type SubscriptionRoot {
count(to: Int!, intervalMillis: Int!): Int!

countString(to: Int!, intervalMillis: Int!): ID!
countString(to: Int!, intervalMillis: Int!): String!

secondsSinceEpoch(intervalMillis: Int!): Float!

operationError: ID!
operationError: String!

graphqlAccessError(after: Int!): Int

closeWebSocket: ID!
closeWebSocket: String!

state(intervalMillis: Int!): State!

valueSharedWithSubscriptions: Int!
}

type State {
tag: ID!
tag: String!

subscriptionId: ID!
subscriptionId: String!
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package com.apollographql.apollo.sample.server
import com.apollographql.apollo.sample.server.graphql.SubscriptionRoot
import com.apollographql.apollo.api.ExecutionContext
import com.apollographql.execution.ExecutableSchema
import com.apollographql.execution.parseGetGraphQLRequest
import com.apollographql.execution.parsePostGraphQLRequest
import com.apollographql.execution.parseGraphQLRequest
import com.apollographql.execution.parseGraphQLRequest
import com.apollographql.execution.websocket.ConnectionInitAck
import com.apollographql.execution.websocket.ConnectionInitError
import com.apollographql.execution.websocket.ConnectionInitHandler
Expand Down Expand Up @@ -59,8 +59,8 @@ class GraphQLHttpHandler(private val executableSchema: ExecutableSchema, private
override fun invoke(request: Request): Response {

val graphQLRequestResult = when (request.method) {
Method.GET -> request.uri.toString().parseGetGraphQLRequest()
Method.POST -> request.body.stream.source().buffer().use { it.parsePostGraphQLRequest() }
Method.GET -> request.uri.toString().parseGraphQLRequest()
Method.POST -> request.body.stream.source().buffer().use { it.parseGraphQLRequest() }
else -> error("")
}

Expand Down
Loading
Loading