From 3d32db3c7239f51519332251f268465d1b139c67 Mon Sep 17 00:00:00 2001 From: Kai Oelfke Date: Tue, 4 Oct 2022 13:22:09 +0200 Subject: [PATCH 1/5] Add AsyncOperation tests --- .../Unit/AsyncOperationTests.swift | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 Tests/AlgoliaSearchClientTests/Unit/AsyncOperationTests.swift diff --git a/Tests/AlgoliaSearchClientTests/Unit/AsyncOperationTests.swift b/Tests/AlgoliaSearchClientTests/Unit/AsyncOperationTests.swift new file mode 100644 index 000000000..36c5fe552 --- /dev/null +++ b/Tests/AlgoliaSearchClientTests/Unit/AsyncOperationTests.swift @@ -0,0 +1,133 @@ +import XCTest +@testable import AlgoliaSearchClient + +final class AsyncOperationTests: XCTestCase { + + class TestOperation: AsyncOperation { + override func main() { + work() + } + + private func work() { + DispatchQueue.global().asyncAfter(deadline: .now() + DispatchTimeInterval.milliseconds(200)) { + self.state = .finished + } + } + } + + func testCancellation_withoutQueue() { + let operation = TestOperation() + XCTAssertTrue(operation.isReady) + operation.cancel() + XCTAssertTrue(operation.isCancelled) + operation.start() + XCTAssertTrue(operation.isFinished) + } + + func testCancellation_updatesIsCancelled_whenCancelledBeforeEnqueuing() { + let operation = TestOperation() + let queue = OperationQueue() + operation.cancel() + queue.addOperation(operation) + queue.waitUntilAllOperationsAreFinished() + XCTAssertTrue(operation.isCancelled) + XCTAssertTrue(operation.isFinished) + } + + func testCancellation_updatesIsCancelled_whenCancelledAfterEnqueuing() { + let operation = TestOperation() + let queue = OperationQueue() + queue.addOperation(operation) + operation.cancel() + queue.waitUntilAllOperationsAreFinished() + XCTAssertTrue(operation.isCancelled) + XCTAssertTrue(operation.isFinished) + } + + func testCancellation_updatesIsCancelled_whenOperationIsRunning() { + let queue = OperationQueue() + let operation = TestOperation() + queue.addOperation(operation) + Thread.sleep(forTimeInterval: 0.1) + XCTAssertTrue(operation.isExecuting) + operation.cancel() + XCTAssertFalse(operation.isFinished) + queue.waitUntilAllOperationsAreFinished() + XCTAssertTrue(operation.isCancelled) + XCTAssertTrue(operation.isFinished) + } + + func testCancellation_ignoresCancellation_whenOperationIsFinished() { + let queue = OperationQueue() + let operation = TestOperation() + queue.addOperation(operation) + queue.waitUntilAllOperationsAreFinished() + XCTAssertTrue(operation.isFinished) + operation.cancel() + XCTAssertFalse(operation.isCancelled) + } + + // Behavior of standard Operation without subclassing. + func testCancellation_ofBlockOperation_withoutQueue() { + let operation = BlockOperation { + Thread.sleep(forTimeInterval: 0.1) + } + XCTAssertTrue(operation.isReady) + operation.cancel() + XCTAssertTrue(operation.isCancelled) + operation.start() + XCTAssertTrue(operation.isFinished) + } + + func testCancellation_ofBlockOperation_updatesIsCancelled_whenCancelledBeforeEnqueuing() { + let operation = BlockOperation { + Thread.sleep(forTimeInterval: 0.1) + } + let queue = OperationQueue() + operation.cancel() + queue.addOperation(operation) + queue.waitUntilAllOperationsAreFinished() + XCTAssertTrue(operation.isCancelled) + XCTAssertTrue(operation.isFinished) + } + + func testCancellation_ofBlockOperation_updatesIsCancelled_whenCancelledAfterEnqueuing() { + let operation = BlockOperation { + Thread.sleep(forTimeInterval: 0.1) + } + let queue = OperationQueue() + queue.addOperation(operation) + operation.cancel() + queue.waitUntilAllOperationsAreFinished() + XCTAssertTrue(operation.isCancelled) + XCTAssertTrue(operation.isFinished) + } + + func testCancellation_ofBlockOperation_updatesIsCancelled_whenOperationIsRunning() { + let queue = OperationQueue() + let operation = BlockOperation { + Thread.sleep(forTimeInterval: 0.2) + } + queue.addOperation(operation) + Thread.sleep(forTimeInterval: 0.1) + XCTAssertTrue(operation.isExecuting) + operation.cancel() + XCTAssertFalse(operation.isFinished) + queue.waitUntilAllOperationsAreFinished() + XCTAssertTrue(operation.isCancelled) + XCTAssertTrue(operation.isFinished) + } + + func testCancellation_ofBlockOperation_ignoresCancellation_whenOperationIsFinished() { + let queue = OperationQueue() + let operation = BlockOperation { + Thread.sleep(forTimeInterval: 0.1) + } + queue.addOperation(operation) + queue.waitUntilAllOperationsAreFinished() + XCTAssertTrue(operation.isFinished) + operation.cancel() + XCTAssertFalse(operation.isCancelled) + } + +} From d45e6db823a02f1292b3ceb7d81cdc33b48d617f Mon Sep 17 00:00:00 2001 From: Kai Oelfke Date: Tue, 4 Oct 2022 13:23:04 +0200 Subject: [PATCH 2/5] Add two cancellation solutions for AsyncOperation --- .../Async/AsyncOperation.swift | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/Sources/AlgoliaSearchClient/Async/AsyncOperation.swift b/Sources/AlgoliaSearchClient/Async/AsyncOperation.swift index 421859af7..f814f2238 100644 --- a/Sources/AlgoliaSearchClient/Async/AsyncOperation.swift +++ b/Sources/AlgoliaSearchClient/Async/AsyncOperation.swift @@ -55,8 +55,20 @@ open class AsyncOperation: Operation { state = .executing } - open override func cancel() { - state = .finished - } + // Approach one, just use Operation.cancel() + + // Approach two, override isCancelled and the cancel function + +// private var _isCancelled: Bool = false +// +// override open var isCancelled: Bool { +// _isCancelled +// } +// +// open override func cancel() { +// if state != .finished { +// _isCancelled = true +// } +// } } From cf7b4b572cfec52b834690acd1c017419d7ec7e1 Mon Sep 17 00:00:00 2001 From: Kai Oelfke Date: Tue, 4 Oct 2022 13:25:28 +0200 Subject: [PATCH 3/5] Update result in HTTPRequest when operation is cancelled Without setting the result the completion handler will never be called, but users of the API should expect a callback with a cancellation error as failure result. --- Sources/AlgoliaSearchClient/Transport/HTTP/HTTPRequest.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/AlgoliaSearchClient/Transport/HTTP/HTTPRequest.swift b/Sources/AlgoliaSearchClient/Transport/HTTP/HTTPRequest.swift index f3ba58cbb..a1c3b438d 100644 --- a/Sources/AlgoliaSearchClient/Transport/HTTP/HTTPRequest.swift +++ b/Sources/AlgoliaSearchClient/Transport/HTTP/HTTPRequest.swift @@ -70,6 +70,7 @@ class HTTPRequest: AsyncOperation, ResultContai guard !isCancelled else { Logger.loggingService.log(level: .debug, message: "Request was cancelled") + result = .failure(SyncOperationError.cancelled) return } From 42c43dd7befa0ee22c44061c13cdffdf87cd475c Mon Sep 17 00:00:00 2001 From: Vladislav Fitc Date: Thu, 22 Jun 2023 21:46:07 +0200 Subject: [PATCH 4/5] chore: update CI triggering (#821) --- .github/workflows/carthage.yml | 6 +++++- .github/workflows/lint.yml | 6 +++++- .github/workflows/pods.yml | 8 ++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/workflows/carthage.yml b/.github/workflows/carthage.yml index 0f189d619..13b129541 100644 --- a/.github/workflows/carthage.yml +++ b/.github/workflows/carthage.yml @@ -1,5 +1,9 @@ name: Carthage -on: [pull_request] +on: + push: + branches: + master + pull_request: jobs: check: runs-on: macos-12 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 13c4171a9..560552b83 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -1,5 +1,9 @@ name: SwiftLint -on: [push] +on: + push: + branches: + master + pull_request: jobs: lint: runs-on: ubuntu-latest diff --git a/.github/workflows/pods.yml b/.github/workflows/pods.yml index 8c80a3c58..37c0e08a1 100644 --- a/.github/workflows/pods.yml +++ b/.github/workflows/pods.yml @@ -1,5 +1,9 @@ -name: Cocoapods lint -on: [pull_request] +name: Cocoapods +on: + push: + branches: + master + pull_request: jobs: lint: runs-on: macos-12 From da067aba35301370e917d721c7dba263916a3d56 Mon Sep 17 00:00:00 2001 From: Kai Oelfke Date: Fri, 21 Jul 2023 11:10:41 +0200 Subject: [PATCH 5/5] Remove commented approach two --- .../Async/AsyncOperation.swift | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/Sources/AlgoliaSearchClient/Async/AsyncOperation.swift b/Sources/AlgoliaSearchClient/Async/AsyncOperation.swift index f814f2238..23c094c33 100644 --- a/Sources/AlgoliaSearchClient/Async/AsyncOperation.swift +++ b/Sources/AlgoliaSearchClient/Async/AsyncOperation.swift @@ -54,21 +54,4 @@ open class AsyncOperation: Operation { main() state = .executing } - - // Approach one, just use Operation.cancel() - - // Approach two, override isCancelled and the cancel function - -// private var _isCancelled: Bool = false -// -// override open var isCancelled: Bool { -// _isCancelled -// } -// -// open override func cancel() { -// if state != .finished { -// _isCancelled = true -// } -// } - }