diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 81ac778df86..1e5a3b7340d 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -41,3 +41,21 @@ jobs: with: name: "Integration tests" matrix_linux_command: "apt-get update -y -q && apt-get install -y -q lsof dnsutils netcat-openbsd net-tools curl jq && ./scripts/integration_tests.sh" + + vsock-tests: + name: Vsock tests + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Load vsock_loopback kernel module + run: sudo modprobe vsock_loopback + - name: Build package tests + run: swift build --build-tests + - name: Run Vsock tests + shell: bash # explicitly choose bash, which ensures -o pipefail + run: swift test --filter "(?i)vsock" | tee test.out + - name: Check for skipped tests + run: test -r test.out && ! grep -i skipped test.out diff --git a/Sources/NIOPosix/VsockAddress.swift b/Sources/NIOPosix/VsockAddress.swift index 40b33673ae4..437bbba0aab 100644 --- a/Sources/NIOPosix/VsockAddress.swift +++ b/Sources/NIOPosix/VsockAddress.swift @@ -217,7 +217,7 @@ extension VsockAddress.ContextID { /// - On Darwin, the `ioctl()` request operates on a socket. /// - On Linux, the `ioctl()` request operates on the `/dev/vsock` device. /// - /// - Note: On Linux, ``local`` may be a better choice. + /// - Note: The semantics of this `ioctl` vary between vsock transports on Linux; ``local`` may be more suitable. static func getLocalContextID(_ socketFD: NIOBSDSocket.Handle) throws -> Self { #if canImport(Darwin) let request = CNIODarwin_IOCTL_VM_SOCKETS_GET_LOCAL_CID diff --git a/Tests/NIOPosixTests/AsyncChannelBootstrapTests.swift b/Tests/NIOPosixTests/AsyncChannelBootstrapTests.swift index 62dfbbc291f..e1dc3d215b6 100644 --- a/Tests/NIOPosixTests/AsyncChannelBootstrapTests.swift +++ b/Tests/NIOPosixTests/AsyncChannelBootstrapTests.swift @@ -1141,7 +1141,7 @@ final class AsyncChannelBootstrapTests: XCTestCase { // MARK: VSock func testVSock() async throws { - try XCTSkipUnless(System.supportsVsock, "No vsock transport available") + try XCTSkipUnless(System.supportsVsockLoopback, "No vsock loopback transport available") let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 3) defer { try! eventLoopGroup.syncShutdownGracefully() diff --git a/Tests/NIOPosixTests/EchoServerClientTest.swift b/Tests/NIOPosixTests/EchoServerClientTest.swift index f32c15b2847..2be0133d9db 100644 --- a/Tests/NIOPosixTests/EchoServerClientTest.swift +++ b/Tests/NIOPosixTests/EchoServerClientTest.swift @@ -234,7 +234,7 @@ class EchoServerClientTest: XCTestCase { } func testEchoVsock() throws { - try XCTSkipUnless(System.supportsVsock, "No vsock transport available") + try XCTSkipUnless(System.supportsVsockLoopback, "No vsock loopback transport available") let group = MultiThreadedEventLoopGroup(numberOfThreads: 1) defer { XCTAssertNoThrow(try group.syncShutdownGracefully()) diff --git a/Tests/NIOPosixTests/TestUtils.swift b/Tests/NIOPosixTests/TestUtils.swift index c6463791564..c2bb121903e 100644 --- a/Tests/NIOPosixTests/TestUtils.swift +++ b/Tests/NIOPosixTests/TestUtils.swift @@ -30,19 +30,10 @@ extension System { } } - static var supportsVsock: Bool { - #if canImport(Darwin) || os(Linux) || os(Android) - guard let socket = try? Socket(protocolFamily: .vsock, type: .stream) else { return false } - XCTAssertNoThrow(try socket.close()) - #if !canImport(Darwin) - do { - let fd = try Posix.open(file: "/dev/vsock", oFlag: O_RDONLY | O_CLOEXEC) - try Posix.close(descriptor: fd) - } catch { - return false - } - #endif - return true + static var supportsVsockLoopback: Bool { + #if os(Linux) || os(Android) + guard let modules = try? String(contentsOf: URL(fileURLWithPath: "/proc/modules")) else { return false } + return modules.split(separator: "\n").compactMap({ $0.split(separator: " ").first }).contains("vsock_loopback") #else return false #endif diff --git a/Tests/NIOPosixTests/VsockAddressTest.swift b/Tests/NIOPosixTests/VsockAddressTest.swift index c32924a8bb0..6c9f44c1017 100644 --- a/Tests/NIOPosixTests/VsockAddressTest.swift +++ b/Tests/NIOPosixTests/VsockAddressTest.swift @@ -58,15 +58,15 @@ class VsockAddressTest: XCTestCase { } func testGetLocalCID() throws { - try XCTSkipUnless(System.supportsVsock) + try XCTSkipUnless(System.supportsVsockLoopback, "No vsock loopback transport available") let socket = try ServerSocket(protocolFamily: .vsock, setNonBlocking: true) defer { try? socket.close() } - // Check the local CID is valid: higher than reserved values, but not VMADDR_CID_ANY. + // Check we can get the local CID using the static property on ContextID. let localCID = try socket.withUnsafeHandle(VsockAddress.ContextID.getLocalContextID) - XCTAssertNotEqual(localCID, .any) - XCTAssertGreaterThan(localCID.rawValue, VsockAddress.ContextID.host.rawValue) + + // Check the local CID from the socket matches. XCTAssertEqual(try socket.getLocalVsockContextID(), localCID) // Check the local CID from the channel option matches.