diff --git a/Tests/WebSocketTests/AutobahnTests.swift b/Tests/WebSocketTests/AutobahnTests.swift index f23e6b8..16fb58b 100644 --- a/Tests/WebSocketTests/AutobahnTests.swift +++ b/Tests/WebSocketTests/AutobahnTests.swift @@ -16,16 +16,17 @@ import Foundation import Logging import NIOConcurrencyHelpers import NIOPosix +import Testing import WSClient import WSCompression -import XCTest /// The Autobahn|Testsuite provides a fully automated test suite to verify client and server /// implementations of The WebSocket Protocol for specification conformance and implementation robustness. /// You can find out more at https://github.com/crossbario/autobahn-testsuite /// /// Before running these tests run `./scripts/autobahn-server.sh` to running the test server. -final class AutobahnTests: XCTestCase { +@Suite(.disabled(if: ci), .serialized) +struct AutobahnTests { /// To run all the autobahn compression tests takes a long time. By default we only run a selection. /// The `AUTOBAHN_ALL_TESTS` environment flag triggers running all of them. var runAllTests: Bool { ProcessInfo.processInfo.environment["AUTOBAHN_ALL_TESTS"] == "true" } @@ -52,7 +53,7 @@ final class AutobahnTests: XCTestCase { return } } - return try result.withLockedValue { try XCTUnwrap($0) } + return try result.withLockedValue { try #require($0) } } /// Run a number of autobahn tests @@ -60,9 +61,6 @@ final class AutobahnTests: XCTestCase { cases: Set, extensions: [WebSocketExtensionFactory] = [.perMessageDeflate(maxDecompressedFrameSize: 16_777_216)] ) async throws { - // These are broken in CI currently - try XCTSkipIf(ProcessInfo.processInfo.environment["CI"] != nil) - struct CaseInfo: Decodable { let id: String let description: String @@ -102,7 +100,7 @@ final class AutobahnTests: XCTestCase { // get case status let status = try await getValue("getCaseStatus?case=\(index)&agent=swift-websocket", as: CaseStatus.self) - XCTAssert(status.behavior == "OK" || status.behavior == "INFORMATIONAL" || status.behavior == "NON-STRICT") + #expect(status.behavior == "OK" || status.behavior == "INFORMATIONAL" || status.behavior == "NON-STRICT") } try await WebSocketClient.connect( @@ -117,27 +115,27 @@ final class AutobahnTests: XCTestCase { } } - func test_1_Framing() async throws { + @Test func test_1_Framing() async throws { try await self.autobahnTests(cases: .init(1..<17)) } - func test_2_PingPongs() async throws { + @Test func test_2_PingPongs() async throws { try await self.autobahnTests(cases: .init(17..<28)) } - func test_3_ReservedBits() async throws { + @Test func test_3_ReservedBits() async throws { try await self.autobahnTests(cases: .init(28..<35)) } - func test_4_Opcodes() async throws { + @Test func test_4_Opcodes() async throws { try await self.autobahnTests(cases: .init(35..<45)) } - func test_5_Fragmentation() async throws { + @Test func test_5_Fragmentation() async throws { try await self.autobahnTests(cases: .init(45..<65)) } - func test_6_UTF8Handling() async throws { + @Test func test_6_UTF8Handling() async throws { // UTF8 validation is available on swift 5.10 or earlier #if compiler(<6) try XCTSkipIf(true) @@ -145,7 +143,7 @@ final class AutobahnTests: XCTestCase { try await self.autobahnTests(cases: .init(65..<210)) } - func test_7_CloseHandling() async throws { + @Test func test_7_CloseHandling() async throws { // UTF8 validation is available on swift 5.10 or earlier #if compiler(<6) try await self.autobahnTests(cases: .init(210..<222)) @@ -155,7 +153,7 @@ final class AutobahnTests: XCTestCase { #endif } - func test_9_Performance() async throws { + @Test func test_9_Performance() async throws { if !self.runAllTests { try await self.autobahnTests(cases: .init([247, 260, 270, 281, 291, 296])) } else { @@ -163,11 +161,11 @@ final class AutobahnTests: XCTestCase { } } - func test_10_AutoFragmentation() async throws { + @Test func test_10_AutoFragmentation() async throws { try await self.autobahnTests(cases: .init([301])) } - func test_12_CompressionDifferentPayloads() async throws { + @Test func test_12_CompressionDifferentPayloads() async throws { if !self.runAllTests { try await self.autobahnTests(cases: .init([302, 330, 349, 360, 388])) } else { @@ -175,7 +173,7 @@ final class AutobahnTests: XCTestCase { } } - func test_13_CompressionDifferentParameters() async throws { + @Test func test_13_CompressionDifferentParameters() async throws { if !self.runAllTests { try await self.autobahnTests( cases: .init([392]), @@ -255,3 +253,5 @@ final class AutobahnTests: XCTestCase { } } } + +var ci: Bool { ProcessInfo.processInfo.environment["CI"] != nil } diff --git a/Tests/WebSocketTests/ClientChannelTests.swift b/Tests/WebSocketTests/ClientChannelTests.swift index 42023f9..a3d6a71 100644 --- a/Tests/WebSocketTests/ClientChannelTests.swift +++ b/Tests/WebSocketTests/ClientChannelTests.swift @@ -13,17 +13,17 @@ //===----------------------------------------------------------------------===// import Logging -import XCTest +import Testing @testable import WSClient -final class ClientChannelTests: XCTestCase { +struct ClientChannelTests { - func testInitialRequestHeader() async throws { + @Test func testInitialRequestHeader() async throws { let ws = try WebSocketClientChannel(handler: { _, _, _ in }, url: "wss://echo.websocket.org:443/ws", configuration: .init()) - XCTAssertEqual(ws.urlPath, "/ws") - XCTAssertEqual(ws.hostHeader, "echo.websocket.org:443") - XCTAssertEqual(ws.originHeader, "wss://echo.websocket.org") + #expect(ws.urlPath == "/ws") + #expect(ws.hostHeader == "echo.websocket.org:443") + #expect(ws.originHeader == "wss://echo.websocket.org") } } diff --git a/Tests/WebSocketTests/ClientTests.swift b/Tests/WebSocketTests/ClientTests.swift index 97ef8d2..3ce07a2 100644 --- a/Tests/WebSocketTests/ClientTests.swift +++ b/Tests/WebSocketTests/ClientTests.swift @@ -16,12 +16,12 @@ import Logging import NIOCore import NIOSSL import NIOWebSocket +import Testing import WSClient -import XCTest -final class WebSocketClientTests: XCTestCase { +struct WebSocketClientTests { - func testEchoServer() async throws { + @Test func testEchoServer() async throws { let clientLogger = { var logger = Logger(label: "client") logger.logLevel = .trace @@ -40,7 +40,7 @@ final class WebSocketClientTests: XCTestCase { } } - func testEchoServerWithSNIHostname() async throws { + @Test func testEchoServerWithSNIHostname() async throws { let clientLogger = { var logger = Logger(label: "client") logger.logLevel = .trace diff --git a/Tests/WebSocketTests/WebSocketExtensionNegotiationTests.swift b/Tests/WebSocketTests/WebSocketExtensionNegotiationTests.swift index 1fd346c..19f4517 100644 --- a/Tests/WebSocketTests/WebSocketExtensionNegotiationTests.swift +++ b/Tests/WebSocketTests/WebSocketExtensionNegotiationTests.swift @@ -14,58 +14,54 @@ import HTTPTypes import NIOWebSocket -import XCTest +import Testing @testable import WSCompression @testable import WSCore -final class WebSocketExtensionNegotiationTests: XCTestCase { - func testExtensionHeaderParsing() { +struct WebSocketExtensionNegotiationTests { + @Test func testExtensionHeaderParsing() { let headers: HTTPFields = .init([ .init(name: .secWebSocketExtensions, value: "permessage-deflate; client_max_window_bits; server_max_window_bits=10"), .init(name: .secWebSocketExtensions, value: "permessage-deflate;client_max_window_bits"), ]) let extensions = WebSocketExtensionHTTPParameters.parseHeaders(headers) - XCTAssertEqual( - extensions, - [ + #expect( + extensions == [ .init("permessage-deflate", parameters: ["client_max_window_bits": .null, "server_max_window_bits": .value("10")]), .init("permessage-deflate", parameters: ["client_max_window_bits": .null]), ] ) } - func testDeflateServerResponse() { + @Test func testDeflateServerResponse() { let requestHeaders: [WebSocketExtensionHTTPParameters] = [ .init("permessage-deflate", parameters: ["client_max_window_bits": .value("10")]) ] let ext = PerMessageDeflateExtensionBuilder(clientNoContextTakeover: true, serverNoContextTakeover: true) let serverResponse = ext.serverResponseHeader(to: requestHeaders) - XCTAssertEqual( - serverResponse, - "permessage-deflate;client_max_window_bits=10;client_no_context_takeover;server_no_context_takeover" + #expect( + serverResponse == "permessage-deflate;client_max_window_bits=10;client_no_context_takeover;server_no_context_takeover" ) } - func testDeflateServerResponseClientMaxWindowBits() { + @Test func testDeflateServerResponseClientMaxWindowBits() { let requestHeaders: [WebSocketExtensionHTTPParameters] = [ .init("permessage-deflate", parameters: ["client_max_window_bits": .null]) ] let ext1 = PerMessageDeflateExtensionBuilder(serverNoContextTakeover: true) let serverResponse1 = ext1.serverResponseHeader(to: requestHeaders) - XCTAssertEqual( - serverResponse1, - "permessage-deflate;server_no_context_takeover" + #expect( + serverResponse1 == "permessage-deflate;server_no_context_takeover" ) let ext2 = PerMessageDeflateExtensionBuilder(clientNoContextTakeover: true, serverMaxWindow: 12) let serverResponse2 = ext2.serverResponseHeader(to: requestHeaders) - XCTAssertEqual( - serverResponse2, - "permessage-deflate;client_no_context_takeover;server_max_window_bits=12" + #expect( + serverResponse2 == "permessage-deflate;client_no_context_takeover;server_max_window_bits=12" ) } - func testUnregonisedExtensionServerResponse() throws { + @Test func testUnregonisedExtensionServerResponse() throws { let serverExtensions: [WebSocketExtensionBuilder] = [PerMessageDeflateExtensionBuilder()] let (headers, extensions) = try serverExtensions.serverExtensionNegotiation( requestHeaders: [ @@ -73,20 +69,19 @@ final class WebSocketExtensionNegotiationTests: XCTestCase { .secWebSocketExtensions: "permessage-deflate;client_max_window_bits=10", ] ) - XCTAssertEqual( - headers[.secWebSocketExtensions], - "permessage-deflate;client_max_window_bits=10" + #expect( + headers[.secWebSocketExtensions] == "permessage-deflate;client_max_window_bits=10" ) - XCTAssertEqual(extensions.count, 1) - let firstExtension = try XCTUnwrap(extensions.first) - XCTAssert(firstExtension is PerMessageDeflateExtension) + #expect(extensions.count == 1) + let firstExtension = try #require(extensions.first) + #expect(firstExtension is PerMessageDeflateExtension) let requestExtensions = try serverExtensions.buildClientExtensions(from: headers) - XCTAssertEqual(requestExtensions.count, 1) - XCTAssert(requestExtensions[0] is PerMessageDeflateExtension) + #expect(requestExtensions.count == 1) + #expect(requestExtensions[0] is PerMessageDeflateExtension) } - func testNonNegotiableClientExtension() throws { + @Test func testNonNegotiableClientExtension() throws { struct MyExtension: WebSocketExtension { var name = "my-extension" @@ -106,12 +101,12 @@ final class WebSocketExtensionNegotiationTests: XCTestCase { }.build() ] let clientExtensions = try clientExtensionBuilders.buildClientExtensions(from: [:]) - XCTAssertEqual(clientExtensions.count, 1) - let myExtension = try XCTUnwrap(clientExtensions.first) - XCTAssert(myExtension is MyExtension) + #expect(clientExtensions.count == 1) + let myExtension = try #require(clientExtensions.first) + #expect(myExtension is MyExtension) } - func testNonNegotiableServerExtension() throws { + @Test func testNonNegotiableServerExtension() throws { struct MyExtension: WebSocketExtension { var name = "my-extension" @@ -129,9 +124,9 @@ final class WebSocketExtensionNegotiationTests: XCTestCase { let (headers, serverExtensions) = try serverExtensionBuilders.serverExtensionNegotiation( requestHeaders: [:] ) - XCTAssertEqual(headers.count, 0) - XCTAssertEqual(serverExtensions.count, 1) - let myExtension = try XCTUnwrap(serverExtensions.first) - XCTAssert(myExtension is MyExtension) + #expect(headers.count == 0) + #expect(serverExtensions.count == 1) + let myExtension = try #require(serverExtensions.first) + #expect(myExtension is MyExtension) } } diff --git a/Tests/WebSocketTests/WebSocketStateMachineTests.swift b/Tests/WebSocketTests/WebSocketStateMachineTests.swift index 3328d98..0b65123 100644 --- a/Tests/WebSocketTests/WebSocketStateMachineTests.swift +++ b/Tests/WebSocketTests/WebSocketStateMachineTests.swift @@ -14,11 +14,11 @@ import NIOCore import NIOWebSocket -import XCTest +import Testing @testable import WSCore -final class WebSocketStateMachineTests: XCTestCase { +struct WebSocketStateMachineTests { private func closeFrameData(code: WebSocketErrorCode = .normalClosure, reason: String? = nil) -> ByteBuffer { var buffer = ByteBufferAllocator().buffer(capacity: 2 + (reason?.utf8.count ?? 0)) buffer.write(webSocketErrorCode: code) @@ -28,84 +28,84 @@ final class WebSocketStateMachineTests: XCTestCase { return buffer } - func testClose() { + @Test func testClose() { var stateMachine = WebSocketStateMachine(autoPingSetup: .disabled) guard case .sendClose = stateMachine.close() else { - XCTFail() + Issue.record() return } guard case .doNothing = stateMachine.close() else { - XCTFail() + Issue.record() return } guard case .doNothing = stateMachine.receivedClose(frameData: self.closeFrameData(), validateUTF8: false) else { - XCTFail() + Issue.record() return } guard case .closed(let frame) = stateMachine.state else { - XCTFail() + Issue.record() return } - XCTAssertEqual(frame?.closeCode, .normalClosure) + #expect(frame?.closeCode == .normalClosure) } - func testReceivedClose() { + @Test func testReceivedClose() { var stateMachine = WebSocketStateMachine(autoPingSetup: .disabled) guard case .sendClose(let error) = stateMachine.receivedClose(frameData: closeFrameData(code: .goingAway), validateUTF8: false) else { - XCTFail() + Issue.record() return } - XCTAssertEqual(error, .normalClosure) + #expect(error == .normalClosure) guard case .closed(let frame) = stateMachine.state else { - XCTFail() + Issue.record() return } - XCTAssertEqual(frame?.closeCode, .goingAway) + #expect(frame?.closeCode == .goingAway) } - func testPingLoopNoPong() { + @Test func testPingLoopNoPong() { var stateMachine = WebSocketStateMachine(autoPingSetup: .enabled(timePeriod: .seconds(15))) guard case .sendPing = stateMachine.sendPing() else { - XCTFail() + Issue.record() return } guard case .wait = stateMachine.sendPing() else { - XCTFail() + Issue.record() return } } - func testPingLoop() { + @Test func testPingLoop() { var stateMachine = WebSocketStateMachine(autoPingSetup: .enabled(timePeriod: .seconds(15))) guard case .sendPing(let buffer) = stateMachine.sendPing() else { - XCTFail() + Issue.record() return } guard case .wait = stateMachine.sendPing() else { - XCTFail() + Issue.record() return } stateMachine.receivedPong(frameData: buffer) guard case .open(let openState) = stateMachine.state else { - XCTFail() + Issue.record() return } - XCTAssertEqual(openState.lastPingTime, nil) + #expect(openState.lastPingTime == nil) guard case .sendPing = stateMachine.sendPing() else { - XCTFail() + Issue.record() return } } // Verify ping buffer size doesnt grow - func testPingBufferSize() async throws { + @Test func testPingBufferSize() async throws { var stateMachine = WebSocketStateMachine(autoPingSetup: .enabled(timePeriod: .milliseconds(1))) var currentBuffer = ByteBuffer() var count = 0 while true { switch stateMachine.sendPing() { case .sendPing(let buffer): - XCTAssertEqual(buffer.readableBytes, 16) + #expect(buffer.readableBytes == 16) currentBuffer = buffer count += 1 if count > 4 { @@ -117,11 +117,11 @@ final class WebSocketStateMachineTests: XCTestCase { stateMachine.receivedPong(frameData: currentBuffer) case .closeConnection: - XCTFail("Should not timeout") + Issue.record("Should not timeout") return case .stop: - XCTFail("Should not stop") + Issue.record("Should not stop") return } }