Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
6e7af18
Implement graphql-transport-ws protocol support
calvincestari Feb 18, 2022
d60ae4a
Add graphql-transport-ws integration test based on Apollo Server docs…
calvincestari Feb 18, 2022
685d359
Add CI step for Apollo Server graphql-transport-ws tests
calvincestari Feb 18, 2022
c36b779
After installing node v12 switch to use v16
calvincestari Feb 18, 2022
b1fc644
Instruct nvm to use version in .nvmrc
calvincestari Feb 18, 2022
6768fde
Update documentation and tutorial
calvincestari Feb 18, 2022
e8d1123
Change WSProtocol cases to closer match library names
calvincestari Feb 21, 2022
7f6c4b6
Remove initializer defaults and require web socket protocol on design…
calvincestari Feb 21, 2022
ad9fbb5
Update Subscriptions documentation
calvincestari Feb 21, 2022
37336c5
Add WSProtocol option for AWS AppSync
calvincestari Feb 22, 2022
348dcf0
Add ping/pong message support required by graphql-ws
calvincestari Feb 22, 2022
3391f33
Update documentation and tutorial
calvincestari Feb 23, 2022
5b3aafb
Add tests for subscriptionWsProtocol
calvincestari Feb 24, 2022
6edea9b
Add tests for graphqlWSProtocol
calvincestari Feb 24, 2022
4178c66
Revert to naming aligned with the protocols and not the implementatio…
calvincestari Feb 24, 2022
d63d078
Use longer async timeout for slower environments like CI
calvincestari Feb 24, 2022
fa3f459
Fix test names
calvincestari Feb 24, 2022
118745d
Fix project configuration
calvincestari Feb 25, 2022
3589cad
Rename protocol parameter on WebSocket initializers
calvincestari Feb 25, 2022
2a92350
Revert "Use longer async timeout for slower environments like CI"
calvincestari Feb 25, 2022
9c92529
Fix async timing bug and refactor websocket protocol tests
calvincestari Feb 25, 2022
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
Prev Previous commit
Fix async timing bug and refactor websocket protocol tests
  • Loading branch information
calvincestari committed Feb 25, 2022
commit 9c92529d81d0a9b594a2a8693d2b9a79f6205954
4 changes: 4 additions & 0 deletions Apollo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@
E63C03DF27BDDC3D00D675C6 /* SubscriptionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E63C03DD27BDDC3400D675C6 /* SubscriptionTests.swift */; };
E63C03E227BDE00400D675C6 /* SubscriptionAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E6A901D427BDAFA100931C9E /* SubscriptionAPI.framework */; };
E63C67A327C8AA2A00B1654E /* OperationMessageMatchers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E658546527C6277600339378 /* OperationMessageMatchers.swift */; };
E63F15CD27C96D6D006879ED /* WSProtocolTestsBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = E63F15CC27C96D6D006879ED /* WSProtocolTestsBase.swift */; };
E657CDBA26FD01D4005834D6 /* ApolloSchemaInternalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E657CDB926FD01D4005834D6 /* ApolloSchemaInternalTests.swift */; };
E658545B27C5C1EE00339378 /* Nimble in Frameworks */ = {isa = PBXBuildFile; productRef = E658545A27C5C1EE00339378 /* Nimble */; };
E658545C27C5CA1C00339378 /* SubscriptionAPI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E6A901D427BDAFA100931C9E /* SubscriptionAPI.framework */; };
Expand Down Expand Up @@ -851,6 +852,7 @@
E63C03D627BDBA8900D675C6 /* operation_ids.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = operation_ids.json; sourceTree = "<group>"; };
E63C03DB27BDD99100D675C6 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
E63C03DD27BDDC3400D675C6 /* SubscriptionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionTests.swift; sourceTree = "<group>"; };
E63F15CC27C96D6D006879ED /* WSProtocolTestsBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WSProtocolTestsBase.swift; sourceTree = "<group>"; };
E657CDB926FD01D4005834D6 /* ApolloSchemaInternalTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ApolloSchemaInternalTests.swift; sourceTree = "<group>"; };
E658545D27C6028100339378 /* MockWebSocketDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockWebSocketDelegate.swift; sourceTree = "<group>"; };
E658546527C6277600339378 /* OperationMessageMatchers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationMessageMatchers.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1816,6 +1818,7 @@
19E9F6AA26D58A92003AB80E /* OperationMessageIdCreatorTests.swift */,
E6B9BDDA27C5693300CF911D /* GraphqlWsProtocolTests.swift */,
E658546B27C77B8B00339378 /* GraphqlTransportWsProtocolTests.swift */,
E63F15CC27C96D6D006879ED /* WSProtocolTestsBase.swift */,
);
path = WebSocket;
sourceTree = "<group>";
Expand Down Expand Up @@ -2828,6 +2831,7 @@
9F295E311E27534800A24949 /* NormalizeQueryResults.swift in Sources */,
9FF90A731DDDEB420034C3B6 /* ParseQueryResponseTests.swift in Sources */,
DED45DE9261B96B70086EF63 /* LoadQueryFromStoreTests.swift in Sources */,
E63F15CD27C96D6D006879ED /* WSProtocolTestsBase.swift in Sources */,
9BF6C94325194DE2000D5B93 /* MultipartFormData+Testing.swift in Sources */,
DE181A3426C5D8D4000C0B9C /* CompressionTests.swift in Sources */,
19E9F6AC26D58A9A003AB80E /* OperationMessageIdCreatorTests.swift in Sources */,
Expand Down
77 changes: 11 additions & 66 deletions Tests/ApolloTests/WebSocket/GraphqlTransportWsProtocolTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,15 @@ import Nimble
import Apollo
import SubscriptionAPI

class GraphqlTransportWsProtocolTests: XCTestCase {
private var store: ApolloStore!
private var mockWebSocket: MockWebSocket!
private var websocketTransport: WebSocketTransport! {
didSet {
if let websocketTransport = websocketTransport { // caters for tearDown setting nil value
websocketTransport.websocket.delegate = mockWebSocketDelegate
}
}
}
private var mockWebSocketDelegate: MockWebSocketDelegate!
private var client: ApolloClient!

override func setUp() {
super.setUp()

store = ApolloStore()
}

override func tearDown() {
client = nil
websocketTransport = nil
mockWebSocket = nil
mockWebSocketDelegate = nil
store = nil
class GraphqlTransportWsProtocolTests: WSProtocolTestsBase {

super.tearDown()
}
let `protocol` = "graphql-transport-ws"

// MARK: Helpers

private func buildWebSocket() {
override var urlRequest: URLRequest {
var request = URLRequest(url: TestURL.mockServer.url)
request.setValue("graphql-transport-ws", forHTTPHeaderField: "Sec-WebSocket-Protocol")
request.setValue(`protocol`, forHTTPHeaderField: "Sec-WebSocket-Protocol")

mockWebSocketDelegate = MockWebSocketDelegate()
mockWebSocket = MockWebSocket(request: request)
websocketTransport = WebSocketTransport(websocket: mockWebSocket, store: store)
}

private func buildClient() {
client = ApolloClient(networkTransport: websocketTransport, store: store)
}

private func connectWebSocket() {
websocketTransport.socketConnectionState.mutate { $0 = .connected }
}

private func ackConnection() {
let ackMessage = OperationMessage(type: .connectionAck).rawMessage!
websocketTransport.websocketDidReceiveMessage(socket: mockWebSocket, text: ackMessage)
return request
}

// MARK: Initializer Tests
Expand All @@ -66,7 +24,7 @@ class GraphqlTransportWsProtocolTests: XCTestCase {
request: URLRequest(url: TestURL.mockServer.url),
protocol: .graphql_transport_ws
).request.value(forHTTPHeaderField: "Sec-WebSocket-Protocol")
).to(equal("graphql-transport-ws"))
).to(equal(`protocol`))
}

func test__convenienceInitializers__shouldSetRequestProtocolHeader() {
Expand All @@ -75,15 +33,15 @@ class GraphqlTransportWsProtocolTests: XCTestCase {
url: TestURL.mockServer.url,
protocol: .graphql_transport_ws
).request.value(forHTTPHeaderField: "Sec-WebSocket-Protocol")
).to(equal("graphql-transport-ws"))
).to(equal(`protocol`))

expect(
WebSocket(
url: TestURL.mockServer.url,
writeQueueQOS: .default,
protocol: .graphql_transport_ws
).request.value(forHTTPHeaderField: "Sec-WebSocket-Protocol")
).to(equal("graphql-transport-ws"))
).to(equal(`protocol`))
}

// MARK: Protocol Tests
Expand Down Expand Up @@ -231,12 +189,11 @@ class GraphqlTransportWsProtocolTests: XCTestCase {
}
}

let message = OperationMessage(
self.sendAsync(message: OperationMessage(
payload: ["data": ["numberIncremented": 42]],
id: "1",
type: .next
).rawMessage!
self.websocketTransport.websocketDidReceiveMessage(socket: self.mockWebSocket, text: message)
))
}
}

Expand All @@ -256,19 +213,7 @@ class GraphqlTransportWsProtocolTests: XCTestCase {
}

// when
let message = OperationMessage(payload: ["sample": "data"], type: .ping).rawMessage!
self.websocketTransport.websocketDidReceiveMessage(socket: self.mockWebSocket, text: message)
self.sendAsync(message: OperationMessage(payload: ["sample": "data"], type: .ping))
}
}
}

private extension GraphQLOperation {
var requestBody: GraphQLMap {
ApolloRequestBodyCreator().requestBody(
for: self,
sendOperationIdentifiers: false,
sendQueryDocument: true,
autoPersistQuery: false
)
}
}
74 changes: 10 additions & 64 deletions Tests/ApolloTests/WebSocket/GraphqlWsProtocolTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,15 @@ import Nimble
import Apollo
import SubscriptionAPI

class GraphqlWsProtocolTests: XCTestCase {
private var store: ApolloStore!
private var mockWebSocket: MockWebSocket!
private var websocketTransport: WebSocketTransport! {
didSet {
if let websocketTransport = websocketTransport { // caters for tearDown setting nil value
websocketTransport.websocket.delegate = mockWebSocketDelegate
}
}
}
private var mockWebSocketDelegate: MockWebSocketDelegate!
private var client: ApolloClient!

override func setUp() {
super.setUp()

store = ApolloStore()
}

override func tearDown() {
client = nil
websocketTransport = nil
mockWebSocket = nil
mockWebSocketDelegate = nil
store = nil
class GraphqlWsProtocolTests: WSProtocolTestsBase {

super.tearDown()
}
let `protocol` = "graphql-ws"

// MARK: Helpers

private func buildWebSocket() {
override var urlRequest: URLRequest {
var request = URLRequest(url: TestURL.mockServer.url)
request.setValue("graphql-ws", forHTTPHeaderField: "Sec-WebSocket-Protocol")
request.setValue(`protocol`, forHTTPHeaderField: "Sec-WebSocket-Protocol")

mockWebSocketDelegate = MockWebSocketDelegate()
mockWebSocket = MockWebSocket(request: request)
websocketTransport = WebSocketTransport(websocket: mockWebSocket, store: store)
}

private func buildClient() {
client = ApolloClient(networkTransport: websocketTransport, store: store)
}

private func connectWebSocket() {
websocketTransport.socketConnectionState.mutate { $0 = .connected }
}

private func ackConnection() {
let ackMessage = OperationMessage(type: .connectionAck).rawMessage!
websocketTransport.websocketDidReceiveMessage(socket: mockWebSocket, text: ackMessage)
return request
}

// MARK: Initializer Tests
Expand All @@ -66,7 +24,7 @@ class GraphqlWsProtocolTests: XCTestCase {
request: URLRequest(url: TestURL.mockServer.url),
protocol: .graphql_ws
).request.value(forHTTPHeaderField: "Sec-WebSocket-Protocol")
).to(equal("graphql-ws"))
).to(equal(`protocol`))
}

func test__convenienceInitializers__shouldSetRequestProtocolHeader() {
Expand All @@ -75,15 +33,15 @@ class GraphqlWsProtocolTests: XCTestCase {
url: TestURL.mockServer.url,
protocol: .graphql_ws
).request.value(forHTTPHeaderField: "Sec-WebSocket-Protocol")
).to(equal("graphql-ws"))
).to(equal(`protocol`))

expect(
WebSocket(
url: TestURL.mockServer.url,
writeQueueQOS: .default,
protocol: .graphql_ws
).request.value(forHTTPHeaderField: "Sec-WebSocket-Protocol")
).to(equal("graphql-ws"))
).to(equal(`protocol`))
}

// MARK: Protocol Tests
Expand Down Expand Up @@ -231,23 +189,11 @@ class GraphqlWsProtocolTests: XCTestCase {
}
}

let message = OperationMessage(
self.sendAsync(message: OperationMessage(
payload: ["data": ["numberIncremented": 42]],
id: "1",
type: .data
).rawMessage!
self.websocketTransport.websocketDidReceiveMessage(socket: self.mockWebSocket, text: message)
))
}
}
}

private extension GraphQLOperation {
var requestBody: GraphQLMap {
ApolloRequestBodyCreator().requestBody(
for: self,
sendOperationIdentifiers: false,
sendQueryDocument: true,
autoPersistQuery: false
)
}
}
81 changes: 81 additions & 0 deletions Tests/ApolloTests/WebSocket/WSProtocolTestsBase.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import XCTest
@testable import ApolloWebSocket
import ApolloTestSupport
import Nimble
import Apollo
import SubscriptionAPI

class WSProtocolTestsBase: XCTestCase {
private var store: ApolloStore!
var mockWebSocket: MockWebSocket!
var websocketTransport: WebSocketTransport! {
didSet {
if let websocketTransport = websocketTransport { // caters for tearDown setting nil value
websocketTransport.websocket.delegate = mockWebSocketDelegate
}
}
}
var mockWebSocketDelegate: MockWebSocketDelegate!
var client: ApolloClient!

override func setUp() {
super.setUp()

store = ApolloStore()
}

override func tearDown() {
client = nil
websocketTransport = nil
mockWebSocket = nil
mockWebSocketDelegate = nil
store = nil

super.tearDown()
}

// MARK: Helpers

var urlRequest: URLRequest {
fatalError("Subclasses must override this property!")
}

func buildWebSocket() {
mockWebSocketDelegate = MockWebSocketDelegate()
mockWebSocket = MockWebSocket(request: urlRequest)
websocketTransport = WebSocketTransport(websocket: mockWebSocket, store: store)
}

func buildClient() {
client = ApolloClient(networkTransport: websocketTransport, store: store)
}

func connectWebSocket() {
websocketTransport.socketConnectionState.mutate { $0 = .connected }
}

func ackConnection() {
let ackMessage = OperationMessage(type: .connectionAck).rawMessage!
websocketTransport.websocketDidReceiveMessage(socket: mockWebSocket, text: ackMessage)
}

func sendAsync(message: OperationMessage) {
websocketTransport.processingQueue.async {
self.websocketTransport.websocketDidReceiveMessage(
socket: self.mockWebSocket,
text: message.rawMessage!
)
}
}
}

extension GraphQLOperation {
var requestBody: GraphQLMap {
ApolloRequestBodyCreator().requestBody(
for: self,
sendOperationIdentifiers: false,
sendQueryDocument: true,
autoPersistQuery: false
)
}
}