Repository: apple/swift-nio
File: Tests/NIOPosixTests/EventLoopTest.swift (Swift)

Code before:
            numberOfThreads: 3
        ) { group in
            do {
                try await group.shutdownGracefully()
                XCTFail("shutdown worked, it shouldn't have")
            } catch EventLoopError.unsupportedOperation {
                // okay
                return Array(group.makeIterator()).count
            }
            return -1
        }
        XCTAssertEqual(3, threadCount)
    }

    func testStructuredConcurrencyMTELGStartStopCanDoBasicAsyncStuff() async throws {
        let actual = try await MultiThreadedEventLoopGroup.withEventLoopGroup(
            numberOfThreads: 3
        ) { group in
            try await group.any().scheduleTask(in: .milliseconds(10), { "cool" }).futureResult.get()
        }
        XCTAssertEqual("cool", actual)
    }
    #endif
}

private final class EventLoopWithPreSucceededFuture: EventLoop {
    var inEventLoop: Bool {
        true
    }

    func execute(_ task: @escaping () -> Void) {
        preconditionFailure("not implemented")
    }

    func submit<T>(_ task: @escaping () throws -> T) -> EventLoopFuture<T> {
        preconditionFailure("not implemented")
    }

    var now: NIODeadline {
        preconditionFailure("not implemented")
    }

    @discardableResult
    func scheduleTask<T>(deadline: NIODeadline, _ task: @escaping () throws -> T) -> Scheduled<T> {
        preconditionFailure("not implemented")
    }

    @discardableResult
    func scheduleTask<T>(in: TimeAmount, _ task: @escaping () throws -> T) -> Scheduled<T> {
        preconditionFailure("not implemented")
    }

Review comment (suggestion):
note to reviewers: even `10` reproes basically 100% on my machine. 1000 should be really safe

Code after:
            numberOfThreads: 3
        ) { group in
            do {
                try await group.shutdownGracefully()
                XCTFail("shutdown worked, it shouldn't have")
            } catch EventLoopError.unsupportedOperation {
                // okay
                return Array(group.makeIterator()).count
            }
            return -1
        }
        XCTAssertEqual(3, threadCount)
    }

    func testStructuredConcurrencyMTELGStartStopCanDoBasicAsyncStuff() async throws {
        let actual = try await MultiThreadedEventLoopGroup.withEventLoopGroup(
            numberOfThreads: 3
        ) { group in
            try await group.any().scheduleTask(in: .milliseconds(10), { "cool" }).futureResult.get()
        }
        XCTAssertEqual("cool", actual)
    }
    #endif

    func testRegressionSelectableEventLoopDeadlock() throws {
        let iterations = 1_000
        let loop = MultiThreadedEventLoopGroup.singleton.next() as! SelectableEventLoop
        let threadsReadySem = DispatchSemaphore(value: 0)
        let go = DispatchSemaphore(value: 0)

        let scheduleds = NIOThreadPool.singleton.runIfActive(eventLoop: loop) {
            threadsReadySem.signal()
            go.wait()
            var tasks: [Scheduled<()>] = []
            for _ in 0..<iterations {
                tasks.append(loop.scheduleTask(in: .milliseconds(1)) {})
            }
            return tasks
        }

        let descriptions = NIOThreadPool.singleton.runIfActive(eventLoop: loop) {
            threadsReadySem.signal()
            go.wait()
            var descriptions: [String] = []
            for _ in 0..<iterations {
                descriptions.append(loop.debugDescription)
            }
            return descriptions
        }

        threadsReadySem.wait()