summaryrefslogtreecommitdiffhomepage
path: root/ios/OperationsTests
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2022-09-25 16:34:23 +0200
committerAndrej Mihajlov <and@mullvad.net>2022-09-26 16:35:38 +0200
commitf389956c2cd884df142adbf00ff2ac7e2f69c2b2 (patch)
tree5f7d4869324760eb4ba0107c0356edc89efd1457 /ios/OperationsTests
parent2e83b1ca27ff243a615ff10c94c20840b38dfd45 (diff)
downloadmullvadvpn-f389956c2cd884df142adbf00ff2ac7e2f69c2b2.tar.xz
mullvadvpn-f389956c2cd884df142adbf00ff2ac7e2f69c2b2.zip
Move AsyncOperation into Operations static library and add separate tests
Diffstat (limited to 'ios/OperationsTests')
-rw-r--r--ios/OperationsTests/OperationConditionTests.swift144
-rw-r--r--ios/OperationsTests/OperationInputInjectionTests.swift89
-rw-r--r--ios/OperationsTests/OperationObserverTests.swift67
-rw-r--r--ios/OperationsTests/OperationSmokeTests.swift38
4 files changed, 338 insertions, 0 deletions
diff --git a/ios/OperationsTests/OperationConditionTests.swift b/ios/OperationsTests/OperationConditionTests.swift
new file mode 100644
index 0000000000..ca4a15f20a
--- /dev/null
+++ b/ios/OperationsTests/OperationConditionTests.swift
@@ -0,0 +1,144 @@
+//
+// OperationConditionTests.swift
+// MullvadVPNTests
+//
+// Created by pronebird on 02/06/2022.
+// Copyright © 2022 Mullvad VPN AB. All rights reserved.
+//
+
+import Operations
+import XCTest
+
+class OperationConditionTests: XCTestCase {
+ func testTrueCondition() {
+ let expectConditionEvaluation = expectation(description: "Expect condition evaluation")
+ let expectOperationToExecute = expectation(description: "Expect operation to execute")
+
+ let operation = AsyncBlockOperation {
+ expectOperationToExecute.fulfill()
+ }
+
+ let blockCondition = BlockCondition { op, completion in
+ expectConditionEvaluation.fulfill()
+ completion(true)
+ }
+
+ operation.addCondition(blockCondition)
+
+ let operationQueue = AsyncOperationQueue()
+ operationQueue.addOperation(operation)
+
+ waitForExpectations(timeout: 1)
+ }
+
+ func testFalseCondition() {
+ let expectConditionEvaluation = expectation(description: "Expect condition evaluation")
+ let expectOperationToNeverExecute = expectation(
+ description: "Expect operation to never execute"
+ )
+ expectOperationToNeverExecute.isInverted = true
+
+ let operation = AsyncBlockOperation {
+ expectOperationToNeverExecute.fulfill()
+ }
+
+ let blockCondition = BlockCondition { op, completion in
+ expectConditionEvaluation.fulfill()
+ completion(false)
+ }
+
+ operation.addCondition(blockCondition)
+
+ let operationQueue = AsyncOperationQueue()
+ operationQueue.addOperation(operation)
+
+ waitForExpectations(timeout: 1)
+ }
+
+ func testNoCancelledDependenciesCondition() {
+ let expectToNeverExecute = expectation(description: "Expect child to never execute.")
+ expectToNeverExecute.isInverted = true
+
+ let parent = BlockOperation()
+ parent.cancel()
+
+ let child = AsyncBlockOperation {
+ expectToNeverExecute.fulfill()
+ }
+ child.addDependency(parent)
+ child.addCondition(NoCancelledDependenciesCondition())
+
+ let operationQueue = AsyncOperationQueue()
+ operationQueue.addOperations([parent, child], waitUntilFinished: false)
+
+ waitForExpectations(timeout: 1)
+ }
+
+ func testNoFailedDependenciesCondition() {
+ let expectToNeverExecute = expectation(description: "Expect child to never execute.")
+ expectToNeverExecute.isInverted = true
+
+ let parent = ResultBlockOperation<Void, URLError> {
+ throw URLError(.badURL)
+ }
+
+ let child = AsyncBlockOperation {
+ expectToNeverExecute.fulfill()
+ }
+ child.addDependency(parent)
+ child.addCondition(NoFailedDependenciesCondition(ignoreCancellations: false))
+
+ let operationQueue = AsyncOperationQueue()
+ operationQueue.addOperations([parent, child], waitUntilFinished: false)
+
+ waitForExpectations(timeout: 1)
+ }
+
+ func testNoFailedDependenciesIgnoringCancellationsCondition() {
+ let expectToExecute = expectation(description: "Expect child to execute.")
+
+ let parent = BlockOperation()
+ parent.cancel()
+
+ let child = AsyncBlockOperation {
+ expectToExecute.fulfill()
+ }
+ child.addDependency(parent)
+ child.addCondition(NoFailedDependenciesCondition(ignoreCancellations: true))
+
+ let operationQueue = AsyncOperationQueue()
+ operationQueue.addOperations([parent, child], waitUntilFinished: false)
+
+ waitForExpectations(timeout: 1)
+ }
+
+ func testMutuallyExclusiveCondition() {
+ let expectFirstOperationExecution = expectation(
+ description: "Expect first operation to execute first"
+ )
+ let expectSecondOperationExecution = expectation(
+ description: "Expect second operation to execute last"
+ )
+
+ let exclusiveCategory = "exclusiveOperations"
+ let operationQueue = AsyncOperationQueue()
+
+ let firstOperation = AsyncBlockOperation { op in
+ DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(1)) {
+ expectFirstOperationExecution.fulfill()
+ op.finish()
+ }
+ }
+ firstOperation.addCondition(MutuallyExclusive(category: exclusiveCategory))
+
+ let secondOperation = AsyncBlockOperation {
+ expectSecondOperationExecution.fulfill()
+ }
+ secondOperation.addCondition(MutuallyExclusive(category: exclusiveCategory))
+
+ operationQueue.addOperations([firstOperation, secondOperation], waitUntilFinished: false)
+
+ let expectations = [expectFirstOperationExecution, expectSecondOperationExecution]
+ wait(for: expectations, timeout: 2, enforceOrder: true)
+ }
+}
diff --git a/ios/OperationsTests/OperationInputInjectionTests.swift b/ios/OperationsTests/OperationInputInjectionTests.swift
new file mode 100644
index 0000000000..828afd2643
--- /dev/null
+++ b/ios/OperationsTests/OperationInputInjectionTests.swift
@@ -0,0 +1,89 @@
+//
+// OperationInputInjectionTests.swift
+// MullvadVPNTests
+//
+// Created by pronebird on 09/06/2022.
+// Copyright © 2022 Mullvad VPN AB. All rights reserved.
+//
+
+import Operations
+import XCTest
+
+class OperationInputInjectionTests: XCTestCase {
+ func testInject() throws {
+ let provider = ResultBlockOperation<Int, Error> {
+ return 1
+ }
+
+ let consumer = TransformOperation<Int, Int, Error> { input in
+ return input + 1
+ }
+
+ consumer.inject(from: provider)
+
+ let operationQueue = AsyncOperationQueue()
+
+ operationQueue.addOperations([provider, consumer], waitUntilFinished: true)
+
+ XCTAssertEqual(consumer.output, 2)
+ }
+
+ func testInjectVia() throws {
+ let provider = ResultBlockOperation<Int, Error> {
+ return 1
+ }
+
+ let consumer = TransformOperation<String, Int, Error> { input in
+ return Int(input)!
+ }
+
+ consumer.inject(from: provider) { output in
+ return "\(output)"
+ }
+
+ let operationQueue = AsyncOperationQueue()
+
+ operationQueue.addOperations([provider, consumer], waitUntilFinished: true)
+
+ XCTAssertEqual(consumer.output, 1)
+ }
+
+ func testInjectMany() throws {
+ struct Context: OperationInputContext {
+ var a: Int?
+ var b: Int?
+
+ func reduce() -> Int? {
+ guard let a = a, let b = b else { return nil }
+
+ return a + b
+ }
+ }
+
+ let operationQueue = AsyncOperationQueue()
+
+ let providerA = ResultBlockOperation<Int, Error> {
+ return 1
+ }
+
+ let providerB = ResultBlockOperation<Int, Error> {
+ return 2
+ }
+
+ let consumer = TransformOperation<Int, String, Error> { input in
+ return "\(input)"
+ }
+
+ consumer.injectMany(context: Context())
+ .inject(from: providerA, assignOutputTo: \.a)
+ .inject(from: providerB, assignOutputTo: \.b)
+ .reduce()
+
+ operationQueue.addOperations(
+ [providerA, providerB, consumer],
+ waitUntilFinished: true
+ )
+
+ XCTAssertEqual(consumer.output, "3")
+ }
+}
diff --git a/ios/OperationsTests/OperationObserverTests.swift b/ios/OperationsTests/OperationObserverTests.swift
new file mode 100644
index 0000000000..c246cdc526
--- /dev/null
+++ b/ios/OperationsTests/OperationObserverTests.swift
@@ -0,0 +1,67 @@
+//
+// OperationObserverTests.swift
+// MullvadVPNTests
+//
+// Created by pronebird on 02/06/2022.
+// Copyright © 2022 Mullvad VPN AB. All rights reserved.
+//
+
+import Operations
+import XCTest
+
+class OperationObserverTests: XCTestCase {
+ func testBlockObserver() throws {
+ let expectDidAttach = expectation(description: "didAttach handler")
+ let expectDidStart = expectation(description: "didStart handler")
+ let expectDidCancel = expectation(description: "didCancel handler")
+ expectDidCancel.isInverted = true
+ let expectDidFinish = expectation(description: "didAttach handler")
+
+ let operation = AsyncBlockOperation()
+ operation.addBlockObserver(OperationBlockObserver(
+ didAttach: { op in
+ expectDidAttach.fulfill()
+ }, didStart: { op in
+ expectDidStart.fulfill()
+ }, didCancel: { op in
+ expectDidCancel.fulfill()
+ }, didFinish: { op, error in
+ expectDidFinish.fulfill()
+ }
+ ))
+
+ let operationQueue = AsyncOperationQueue()
+ operationQueue.addOperation(operation)
+
+ let expectations = [expectDidCancel, expectDidAttach, expectDidStart, expectDidFinish]
+ wait(for: expectations, timeout: 1, enforceOrder: true)
+ }
+
+ func testBlockObserverWithCancelledOperation() {
+ let expectDidAttach = expectation(description: "didAttach handler")
+ let expectDidStart = expectation(description: "didStart handler")
+ expectDidStart.isInverted = true
+ let expectDidCancel = expectation(description: "didCancel handler")
+ let expectDidFinish = expectation(description: "didAttach handler")
+
+ let operation = AsyncBlockOperation()
+ operation.addBlockObserver(OperationBlockObserver(
+ didAttach: { op in
+ expectDidAttach.fulfill()
+ }, didStart: { op in
+ expectDidStart.fulfill()
+ }, didCancel: { op in
+ expectDidCancel.fulfill()
+ }, didFinish: { op, error in
+ expectDidFinish.fulfill()
+ }
+ ))
+ operation.cancel()
+
+ let operationQueue = AsyncOperationQueue()
+ operationQueue.addOperation(operation)
+
+ let expectations = [expectDidAttach, expectDidCancel, expectDidStart, expectDidFinish]
+ wait(for: expectations, timeout: 1, enforceOrder: true)
+ }
+}
diff --git a/ios/OperationsTests/OperationSmokeTests.swift b/ios/OperationsTests/OperationSmokeTests.swift
new file mode 100644
index 0000000000..7d8b17e784
--- /dev/null
+++ b/ios/OperationsTests/OperationSmokeTests.swift
@@ -0,0 +1,38 @@
+//
+// OperationSmokeTests.swift
+// MullvadVPNTests
+//
+// Created by pronebird on 09/06/2022.
+// Copyright © 2022 Mullvad VPN AB. All rights reserved.
+//
+
+import Operations
+import XCTest
+
+class OperationSmokeTests: XCTestCase {
+ func testBatch() {
+ let expect = expectation(description: "Expect all operations to finish.")
+ let operationQueue = AsyncOperationQueue()
+
+ let operations = (1 ... 500).flatMap { i -> [Operation] in
+ let parent = BlockOperation()
+ parent.cancel()
+
+ let child = AsyncBlockOperation {
+ print("Execute block operation \(i)")
+ }
+
+ child.addDependency(parent)
+ child.addCondition(NoFailedDependenciesCondition(ignoreCancellations: true))
+
+ return [parent, child]
+ }
+
+ DispatchQueue.global().async {
+ operationQueue.addOperations(operations, waitUntilFinished: true)
+ expect.fulfill()
+ }
+
+ waitForExpectations(timeout: 1)
+ }
+}