diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2022-09-25 16:34:23 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2022-09-26 16:35:38 +0200 |
| commit | f389956c2cd884df142adbf00ff2ac7e2f69c2b2 (patch) | |
| tree | 5f7d4869324760eb4ba0107c0356edc89efd1457 /ios/OperationsTests | |
| parent | 2e83b1ca27ff243a615ff10c94c20840b38dfd45 (diff) | |
| download | mullvadvpn-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.swift | 144 | ||||
| -rw-r--r-- | ios/OperationsTests/OperationInputInjectionTests.swift | 89 | ||||
| -rw-r--r-- | ios/OperationsTests/OperationObserverTests.swift | 67 | ||||
| -rw-r--r-- | ios/OperationsTests/OperationSmokeTests.swift | 38 |
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) + } +} |
