diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 751a42e2..e4978f70 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: env: DEVELOPER_DIR: /Applications/Xcode_14.3.app/Contents/Developer steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Build run: swift build -v - name: Run tests @@ -25,7 +25,7 @@ jobs: swift: [5.8] container: swift:${{ matrix.swift }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install sqlite run: apt-get -q update && apt-get install -y libsqlite3-dev - name: Build diff --git a/Tests/Alchemy/Queues/QueueTests.swift b/Tests/Alchemy/Queues/QueueTests.swift index 1b9495c4..f2d65664 100644 --- a/Tests/Alchemy/Queues/QueueTests.swift +++ b/Tests/Alchemy/Queues/QueueTests.swift @@ -121,6 +121,37 @@ final class QueueTests: TestCase { XCTAssertEqual(jobData.jobName, "RetryJob", file: file, line: line) XCTAssertEqual(jobData.attempts, 1, file: file, line: line) } + +#if os(Linux) + /// Wait on an array of expectations for up to the specified timeout, and optionally specify whether they + /// must be fulfilled in the given order. May return early based on fulfillment of the waited on expectations. + /// + /// - Parameter expectations: The expectations to wait on. + /// - Parameter timeout: The maximum total time duration to wait on all expectations. + /// - Parameter enforceOrder: Specifies whether the expectations must be fulfilled in the order + /// they are specified in the `expectations` Array. Default is false. + /// - Parameter file: The file name to use in the error message if + /// expectations are not fulfilled before the given timeout. Default is the file + /// containing the call to this method. It is rare to provide this + /// parameter when calling this method. + /// - Parameter line: The line number to use in the error message if the + /// expectations are not fulfilled before the given timeout. Default is the line + /// number of the call to this method in the calling file. It is rare to + /// provide this parameter when calling this method. + /// + /// - SeeAlso: XCTWaiter + func fulfillment(of expectations: [XCTestExpectation], timeout: TimeInterval, enforceOrder: Bool = false) async { + return await withCheckedContinuation { continuation in + // This function operates by blocking a background thread instead of one owned by libdispatch or by the + // Swift runtime (as used by Swift concurrency.) To ensure we use a thread owned by neither subsystem, use + // Foundation's Thread.detachNewThread(_:). + Thread.detachNewThread { [self] in + wait(for: expectations, timeout: timeout, enforceOrder: enforceOrder) + continuation.resume() + } + } + } +#endif } private struct FailureJob: Job, Codable { diff --git a/Tests/Alchemy/_Utilities/Linux+Testing.swift b/Tests/Alchemy/_Utilities/Linux+Testing.swift index a6b8f335..d9fad6fc 100644 --- a/Tests/Alchemy/_Utilities/Linux+Testing.swift +++ b/Tests/Alchemy/_Utilities/Linux+Testing.swift @@ -19,7 +19,6 @@ extension XCTestCase { /// provide this parameter when calling this method. /// /// - SeeAlso: XCTWaiter - @available(macOS 12.0, *) func fulfillment(of expectations: [XCTestExpectation], timeout: TimeInterval, enforceOrder: Bool = false, file: StaticString = #file, line: Int = #line) async { return await withCheckedContinuation { continuation in // This function operates by blocking a background thread instead of one owned by libdispatch or by the