import Logging import NIOCore import NIOPosix import PostgresNIO import Testing @testable import Persistence @Suite( "TLS enumeration", .tags(.enumeration) ) struct TLSTests { // MARK: Methods tests @Test func `off connects in plaintext`() async throws { // With TLS disabled the client skips the `SSLRequest` and sends its startup message directly, // which the fake server answers in plaintext. let server = try await PlaintextPostgresServer.start() let connection = try await connect(to: server, tls: .off) let isConnected = !connection.isClosed try await connection.close() try await server.stop() #expect(isConnected) } @Test func `prefer falls back to plaintext when the server offers no TLS`() async throws { // The fake server refuses the `SSLRequest`, so this connection can only succeed by downgrading // to plaintext — pinning the driver behavior the `prefer` posture relies on. let server = try await PlaintextPostgresServer.start() let connection = try await connect(to: server, tls: .prefer) let isConnected = !connection.isClosed try await connection.close() try await server.stop() #expect(isConnected) } @Test func `require refuses the connection when the server offers no TLS`() async throws { // The fake server refuses the `SSLRequest`, so the driver must fail the connection instead of // downgrading — pinning the refusal the `require` posture promises. let server = try await PlaintextPostgresServer.start() let error = await #expect(throws: PSQLError.self) { _ = try await connect(to: server, tls: .require) } try await server.stop() #expect(error?.code == .sslUnsupported) } } // MARK: - Helpers private extension TLSTests { /// Opens a connection to the given fake server with the given TLS posture. /// - Parameters: /// - server: the fake server to connect to. /// - tls: the TLS posture to connect with. /// - Returns: the open connection, to be closed by the caller. func connect( to server: PlaintextPostgresServer, tls: TLS ) async throws -> PostgresConnection { try await PostgresConnection.connect( on: MultiThreadedEventLoopGroup.singleton.any(), configuration: .init( host: "127.0.0.1", port: server.port, username: "loud", password: "loud", database: "loud", tls: tls.postgresTLS() ), id: 1, logger: Logger(label: "test") ) } }