| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- //
- // WebSocketTests.swift
- // Alamofire
- //
- // Created by Jon Shier on 1/17/21.
- // Copyright © 2021 Alamofire. All rights reserved.
- //
- #if canImport(Darwin) && !canImport(FoundationNetworking)
- import Alamofire
- import Foundation
- import XCTest
- @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
- final class WebSocketTests: BaseTestCase {
- // override var skipVersion: SkipVersion { .twenty }
- func testThatWebSocketsCanReceiveAMessage() {
- // Given
- let didConnect = expectation(description: "didConnect")
- let didReceiveMessage = expectation(description: "didReceiveMessage")
- let didDisconnect = expectation(description: "didDisconnect")
- let didComplete = expectation(description: "didComplete")
- let session = stored(Session())
- var connectedProtocol: String?
- var message: URLSessionWebSocketTask.Message?
- var closeCode: URLSessionWebSocketTask.CloseCode?
- var closeReason: Data?
- var receivedCompletion: WebSocketRequest.Completion?
- // When
- session.websocketRequest(.websocket()).responseMessage { event in
- switch event.kind {
- case let .connected(`protocol`):
- connectedProtocol = `protocol`
- didConnect.fulfill()
- case let .receivedMessage(receivedMessage):
- message = receivedMessage
- didReceiveMessage.fulfill()
- case let .disconnected(code, reason):
- closeCode = code
- closeReason = reason
- didDisconnect.fulfill()
- case let .completed(completion):
- receivedCompletion = completion
- didComplete.fulfill()
- }
- }
- wait(for: [didConnect, didReceiveMessage, didDisconnect, didComplete],
- timeout: timeout,
- enforceOrder: false)
- // Then
- XCTAssertNil(connectedProtocol)
- XCTAssertNotNil(message)
- XCTAssertEqual(closeCode, .normalClosure)
- XCTAssertNil(closeReason)
- XCTAssertNil(receivedCompletion?.error)
- }
- func testThatWebSocketsCanReceiveAMessageWithAProtocol() {
- // Given
- let didConnect = expectation(description: "didConnect")
- let didReceiveMessage = expectation(description: "didReceiveMessage")
- let didDisconnect = expectation(description: "didDisconnect")
- let didComplete = expectation(description: "didComplete")
- let session = stored(Session())
- let `protocol` = "protocol"
- var connectedProtocol: String?
- var message: URLSessionWebSocketTask.Message?
- var closeCode: URLSessionWebSocketTask.CloseCode?
- var closeReason: Data?
- var receivedCompletion: WebSocketRequest.Completion?
- // When
- session.websocketRequest(.websocket(), protocol: `protocol`).responseMessage { event in
- switch event.kind {
- case let .connected(`protocol`):
- connectedProtocol = `protocol`
- didConnect.fulfill()
- case let .receivedMessage(receivedMessage):
- message = receivedMessage
- didReceiveMessage.fulfill()
- case let .disconnected(code, reason):
- closeCode = code
- closeReason = reason
- didDisconnect.fulfill()
- case let .completed(completion):
- receivedCompletion = completion
- didComplete.fulfill()
- }
- }
- wait(for: [didConnect, didReceiveMessage, didDisconnect, didComplete],
- timeout: timeout,
- enforceOrder: true)
- // Then
- XCTAssertEqual(connectedProtocol, `protocol`)
- XCTAssertNotNil(message)
- XCTAssertEqual(closeCode, .normalClosure)
- XCTAssertNil(closeReason)
- XCTAssertNil(receivedCompletion?.error)
- }
- func testThatWebSocketsCanReceiveMultipleMessages() {
- // Given
- let count = 5
- let didConnect = expectation(description: "didConnect")
- let didReceiveMessage = expectation(description: "didReceiveMessage")
- didReceiveMessage.expectedFulfillmentCount = count
- let didDisconnect = expectation(description: "didDisconnect")
- let didComplete = expectation(description: "didComplete")
- let session = stored(Session())
- var connectedProtocol: String?
- var messages: [URLSessionWebSocketTask.Message] = []
- var closeCode: URLSessionWebSocketTask.CloseCode?
- var closeReason: Data?
- var receivedCompletion: WebSocketRequest.Completion?
- // When
- session.websocketRequest(.websocketCount(count)).responseMessage { event in
- switch event.kind {
- case let .connected(`protocol`):
- connectedProtocol = `protocol`
- didConnect.fulfill()
- case let .receivedMessage(receivedMessage):
- messages.append(receivedMessage)
- didReceiveMessage.fulfill()
- case let .disconnected(code, reason):
- closeCode = code
- closeReason = reason
- didDisconnect.fulfill()
- case let .completed(completion):
- receivedCompletion = completion
- didComplete.fulfill()
- }
- }
- wait(for: [didConnect, didReceiveMessage, didDisconnect, didComplete], timeout: timeout, enforceOrder: true)
- // Then
- XCTAssertNil(connectedProtocol)
- XCTAssertEqual(messages.count, count)
- XCTAssertEqual(closeCode, .normalClosure)
- XCTAssertNil(closeReason)
- XCTAssertNil(receivedCompletion?.error)
- }
- func testThatWebSocketsCanSendAndReceiveMessages() {
- // Given
- let didConnect = expectation(description: "didConnect")
- let didSend = expectation(description: "didSend")
- let didReceiveMessage = expectation(description: "didReceiveMessage")
- let didDisconnect = expectation(description: "didDisconnect")
- let didComplete = expectation(description: "didComplete")
- let session = stored(Session())
- let sentMessage = URLSessionWebSocketTask.Message.string("Echo")
- var connectedProtocol: String?
- var message: URLSessionWebSocketTask.Message?
- var closeCode: URLSessionWebSocketTask.CloseCode?
- var closeReason: Data?
- var receivedCompletion: WebSocketRequest.Completion?
- // When
- let request = session.websocketRequest(.websocketEcho)
- request.responseMessage { event in
- switch event.kind {
- case let .connected(`protocol`):
- connectedProtocol = `protocol`
- didConnect.fulfill()
- request.send(sentMessage) { _ in didSend.fulfill() }
- case let .receivedMessage(receivedMessage):
- message = receivedMessage
- event.cancel(with: .normalClosure, reason: nil)
- didReceiveMessage.fulfill()
- case let .disconnected(code, reason):
- closeCode = code
- closeReason = reason
- didDisconnect.fulfill()
- case let .completed(completion):
- receivedCompletion = completion
- didComplete.fulfill()
- }
- }
- wait(for: [didConnect, didSend, didReceiveMessage, didDisconnect, didComplete],
- timeout: timeout,
- enforceOrder: true)
- // Then
- XCTAssertNil(connectedProtocol)
- XCTAssertNotNil(message)
- XCTAssertEqual(sentMessage, message)
- XCTAssertEqual(closeCode, .normalClosure)
- XCTAssertNil(closeReason)
- // XCTAssertNil(receivedCompletion?.error)
- }
- func testOnePingOnly() {
- // Given
- let didConnect = expectation(description: "didConnect")
- let didSend = expectation(description: "didSend")
- let didReceiveMessage = expectation(description: "didReceiveMessage")
- let didReceivePong = expectation(description: "didReceivePong")
- didReceivePong.expectedFulfillmentCount = 100
- let didDisconnect = expectation(description: "didDisconnect")
- let didComplete = expectation(description: "didComplete")
- let session = stored(Session())
- let sentMessage = URLSessionWebSocketTask.Message.string("Echo")
- var connectedProtocol: String?
- var message: URLSessionWebSocketTask.Message?
- var receivedPong: WebSocketRequest.PingResponse.Pong?
- var closeCode: URLSessionWebSocketTask.CloseCode?
- var closeReason: Data?
- var receivedCompletion: WebSocketRequest.Completion?
- // When
- let request = session.websocketRequest(.websocketEcho)
- request.responseMessage { event in
- switch event.kind {
- case let .connected(`protocol`):
- connectedProtocol = `protocol`
- didConnect.fulfill()
- request.send(sentMessage) { _ in didSend.fulfill() }
- case let .receivedMessage(receivedMessage):
- message = receivedMessage
- didReceiveMessage.fulfill()
- for count in 0..<100 {
- request.sendPing { response in
- switch response {
- case let .pong(pong):
- receivedPong = pong
- default:
- break
- }
- didReceivePong.fulfill()
- if count == 99 {
- request.cancel(with: .normalClosure, reason: nil)
- }
- }
- }
- case let .disconnected(code, reason):
- closeCode = code
- closeReason = reason
- didDisconnect.fulfill()
- case let .completed(completion):
- receivedCompletion = completion
- didComplete.fulfill()
- }
- }
- wait(for: [didConnect, didSend, didReceiveMessage, didReceivePong, didDisconnect, didComplete],
- timeout: timeout,
- enforceOrder: true)
- // Then
- XCTAssertNil(connectedProtocol)
- XCTAssertNotNil(message)
- XCTAssertEqual(sentMessage, message)
- XCTAssertEqual(closeCode, .normalClosure)
- XCTAssertNil(closeReason)
- XCTAssertNotNil(receivedCompletion)
- // XCTAssertNil(receivedCompletion?.error)
- XCTAssertNotNil(receivedPong)
- }
- func testThatTimePingsOccur() {
- // Given
- let didConnect = expectation(description: "didConnect")
- let didDisconnect = expectation(description: "didDisconnect")
- let didComplete = expectation(description: "didComplete")
- let session = stored(Session())
- var connectedProtocol: String?
- var closeCode: URLSessionWebSocketTask.CloseCode?
- var closeReason: Data?
- var receivedCompletion: WebSocketRequest.Completion?
- // When
- let request = session.websocketRequest(.websocketPings(), pingInterval: 0.01)
- request.responseMessage { event in
- switch event.kind {
- case let .connected(`protocol`):
- connectedProtocol = `protocol`
- didConnect.fulfill()
- case .receivedMessage:
- break
- case let .disconnected(code, reason):
- closeCode = code
- closeReason = reason
- didDisconnect.fulfill()
- case let .completed(completion):
- receivedCompletion = completion
- didComplete.fulfill()
- }
- }
- wait(for: [didConnect, didDisconnect, didComplete], timeout: timeout, enforceOrder: true)
- // Then
- XCTAssertNil(connectedProtocol)
- XCTAssertEqual(closeCode, .goingAway) // Default Vapor close() code.
- XCTAssertNil(closeReason)
- XCTAssertNotNil(receivedCompletion)
- XCTAssertNil(receivedCompletion?.error)
- }
- func testThatWebSocketFailsWithTooSmallMaximumMessageSize() {
- // Given
- let didConnect = expectation(description: "didConnect")
- let didComplete = expectation(description: "didComplete")
- let session = stored(Session())
- var connectedProtocol: String?
- var receivedCompletion: WebSocketRequest.Completion?
- // When
- session.websocketRequest(.websocket(), maximumMessageSize: 1).responseMessage { event in
- switch event.kind {
- case let .connected(`protocol`):
- connectedProtocol = `protocol`
- didConnect.fulfill()
- case .receivedMessage, .disconnected:
- break
- case let .completed(completion):
- receivedCompletion = completion
- didComplete.fulfill()
- }
- }
- wait(for: [didConnect, didComplete], timeout: timeout, enforceOrder: false)
- // Then
- XCTAssertNil(connectedProtocol)
- XCTAssertNotNil(receivedCompletion?.error)
- }
- func testThatWebSocketsFinishAfterNonNormalResponseCode() {
- // Given
- let didConnect = expectation(description: "didConnect")
- let didReceiveMessage = expectation(description: "didReceiveMessage")
- let didDisconnect = expectation(description: "didDisconnect")
- let didComplete = expectation(description: "didComplete")
- let session = stored(Session())
- var connectedProtocol: String?
- var message: URLSessionWebSocketTask.Message?
- var closeCode: URLSessionWebSocketTask.CloseCode?
- var closeReason: Data?
- var receivedCompletion: WebSocketRequest.Completion?
- // When
- session.websocketRequest(.websocket(closeCode: .goingAway)).responseMessage { event in
- switch event.kind {
- case let .connected(`protocol`):
- connectedProtocol = `protocol`
- didConnect.fulfill()
- case let .receivedMessage(receivedMessage):
- message = receivedMessage
- didReceiveMessage.fulfill()
- case let .disconnected(code, reason):
- closeCode = code
- closeReason = reason
- didDisconnect.fulfill()
- case let .completed(completion):
- receivedCompletion = completion
- didComplete.fulfill()
- }
- }
- wait(for: [didConnect, didReceiveMessage, didDisconnect, didComplete],
- timeout: timeout,
- enforceOrder: false)
- // Then
- XCTAssertNil(connectedProtocol)
- XCTAssertNotNil(message)
- XCTAssertEqual(closeCode, .goingAway)
- XCTAssertNil(closeReason)
- XCTAssertNil(receivedCompletion?.error)
- }
- }
- @available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
- extension URLSessionWebSocketTask.Message: Equatable {
- public static func ==(lhs: URLSessionWebSocketTask.Message, rhs: URLSessionWebSocketTask.Message) -> Bool {
- switch (lhs, rhs) {
- case let (.string(left), .string(right)):
- return left == right
- case let (.data(left), .data(right)):
- return left == right
- default:
- return false
- }
- }
- var string: String? {
- guard case let .string(string) = self else { return nil }
- return string
- }
- var data: Data? {
- guard case let .data(data) = self else { return nil }
- return data
- }
- }
- #endif
|