Hi Team, We are trying to add unit test for subsc...
# apollo-kotlin
m
Hi Team, We are trying to add unit test for subscriptions, but getting below exception:
java.net.ProtocolException: Expected 'Connection' header value 'Upgrade' but was 'close'
Could someone please help regarding how to test GQL subscriptions?
Copy code
Stacktrace:


java.net.ProtocolException: Expected 'Connection' header value 'Upgrade' but was 'close'
	at _COROUTINE._BOUNDARY._(CoroutineDebugging.kt:46)
	at kotlinx.coroutines.channels.BufferedChannel.receive$suspendImpl(BufferedChannel.kt:681)
	at kotlinx.coroutines.channels.BufferedChannel.receive(BufferedChannel.kt)
	at com.apollographql.apollo3.internal.ChannelWrapper.receive(ChannelWrapper.kt)
	at com.apollographql.apollo3.network.ws.DefaultWebSocketEngine$open$3.receive(OkHttpWebSocketEngine.kt:86)
	at com.apollographql.apollo3.network.ws.WsProtocol.receiveMessageMap(WsProtocol.kt:131)
	at com.apollographql.apollo3.network.ws.SubscriptionWsProtocol$connectionInit$2.invokeSuspend(SubscriptionWsProtocol.kt:39)
	at com.apollographql.apollo3.network.ws.SubscriptionWsProtocol$connectionInit$2.invoke(SubscriptionWsProtocol.kt)
	at com.apollographql.apollo3.network.ws.SubscriptionWsProtocol$connectionInit$2.invoke(SubscriptionWsProtocol.kt)
	at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturnIgnoreTimeout(Undispatched.kt:89)
	at kotlinx.coroutines.TimeoutKt.setupTimeout(Timeout.kt:151)
	at kotlinx.coroutines.TimeoutKt.withTimeout(Timeout.kt:46)
	at com.apollographql.apollo3.network.ws.SubscriptionWsProtocol.connectionInit(SubscriptionWsProtocol.kt:38)
	at com.apollographql.apollo3.network.ws.WebSocketNetworkTransport.supervise(WebSocketNetworkTransport.kt:214)
	at com.apollographql.apollo3.network.ws.WebSocketNetworkTransport.access$supervise(WebSocketNetworkTransport.kt:61)
	at com.apollographql.apollo3.network.ws.WebSocketNetworkTransport$supervise$1.invokeSuspend(WebSocketNetworkTransport.kt)
	at com.apollographql.apollo3.network.ws.SubscriptionWsProtocol.connectionInit(SubscriptionWsProtocol.kt:38)
	at com.apollographql.apollo3.network.ws.WebSocketNetworkTransport.supervise(WebSocketNetworkTransport.kt:214)
	at com.apollographql.apollo3.network.ws.WebSocketNetworkTransport$1.invokeSuspend(WebSocketNetworkTransport.kt:98)
Caused by: java.net.ProtocolException: Expected 'Connection' header value 'Upgrade' but was 'close'
	at okhttp3.internal.ws.RealWebSocket.checkUpgradeSuccess$okhttp(RealWebSocket.kt:230)
	at okhttp3.internal.ws.RealWebSocket$connect$1.onResponse(RealWebSocket.kt:170)
	at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.base/java.lang.Thread.run(Unknown Source)
Copy code
Subscription:

val client = ApolloClient.Builder()
client.subscriptionNetworkTransport(
    WebSocketNetworkTransport.Builder()
        .protocol(
            SubscriptionWsProtocol.Factory(connectionPayload = {
                mapOf(
                    "token" to ""
                )
            })
        )
        .serverUrl(serverUrl = endpoint)
        .build()
)
Copy code
public val mockGQLServer: MockServer by lazy { MockServer() }

@Test
fun testSubscribe() = testScope {
    mockGQLServer.enqueue(gqlMockResponse(responseString = "", httpStatusCode = 101))
    val resultFlow = client.subscription(subscription).toFlow()
    resultFlow.test {
        val result = awaitItem()
        awaitComplete()
    }
}
Copy code
private fun gqlMockResponse(responseString: String, httpStatusCode: Int = 200): MockResponse {
    val headers = mapOf(
        "Accept" to "application/json",
        "Content-Type" to "application/json",
        "Connection" to "Upgrade",
        "Upgrade" to "websocket"
    )
    return MockResponse.Builder()
        .body(responseString)
        .statusCode(httpStatusCode)
        .headers(
            headers
        ).build()
}
m
Testing WebSockets is not easy. You’ll need the 4.0.0 betas if you’re using
apollo-mockserver
for WebSocket support.
You can take a look at this integration test for an example
In particular, you’ll want
mockServer.enqueueWebSocket()
instead of just
enqueue()
Also note that those APIs are mainly used internally for Apollo Kotlin integration tests. While they are publicly available, they are a lot more unstable compared to the usual
ApolloClient
, etc.. APIs
Another option is to build your own server using Ktor or something similar
m
Thanks @mbonnin 👍