From 547f7943c3ea53cd9a8ec94624fd729a67efb7da Mon Sep 17 00:00:00 2001 From: gmbnt Date: Thu, 2 Apr 2020 15:48:42 +1100 Subject: [PATCH] Add more onion request tests --- SignalServiceKit/src/Loki/API/LokiAPI.swift | 4 +- .../API/Onion Requests/OnionRequestAPI.swift | 2 + .../Onion Requests/OnionRequestAPITests.swift | 43 ++++++++++++++++--- 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/LokiAPI.swift b/SignalServiceKit/src/Loki/API/LokiAPI.swift index d9913ce56..d2aa1ca18 100644 --- a/SignalServiceKit/src/Loki/API/LokiAPI.swift +++ b/SignalServiceKit/src/Loki/API/LokiAPI.swift @@ -2,7 +2,7 @@ import PromiseKit @objc(LKAPI) public final class LokiAPI : NSObject { - private static let stateQueue = DispatchQueue(label: "stateQueue") + private static let stateQueue = DispatchQueue(label: "LokiAPI.stateQueue") /// Only ever modified from the message processing queue (`OWSBatchMessageProcessor.processingQueue`). private static var syncMessageTimestamps: [String:Set] = [:] @@ -22,7 +22,7 @@ public final class LokiAPI : NSObject { } /// All service node related errors must be handled on this queue to avoid race conditions maintaining e.g. failure counts. - public static let errorHandlingQueue = DispatchQueue(label: "errorHandlingQueue") + public static let errorHandlingQueue = DispatchQueue(label: "LokiAPI.errorHandlingQueue") // MARK: Convenience internal static let storage = OWSPrimaryStorage.shared() diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift index ef5823d97..6cb8f4260 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift @@ -123,6 +123,8 @@ internal enum OnionRequestAPI { } /// Returns a `Path` to be used for building an onion request. Builds new paths as needed. + /// + /// - Note: Exposed for testing purposes. internal static func getPath() -> Promise { guard pathSize >= 1 else { preconditionFailure("Cannot build path of size zero.") } // randomElement() uses the system's default random generator, which is cryptographically secure diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPITests.swift b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPITests.swift index 4456a9bc0..0ebef0106 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPITests.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPITests.swift @@ -1,13 +1,13 @@ +import PromiseKit @testable import SignalServiceKit import XCTest class OnionRequestAPITests : XCTestCase { - private let maxRetryCount: UInt = 2 // Be a bit more stringent when testing - func testGetPath() { + func testPathBuilding() { let semaphore = DispatchSemaphore(value: 0) var error: Error? = nil - let _ = OnionRequestAPI.getPath().retryingIfNeeded(maxRetryCount: maxRetryCount).done(on: OnionRequestAPI.workQueue) { _ in + let _ = OnionRequestAPI.getPath().done(on: OnionRequestAPI.workQueue) { _ in semaphore.signal() }.catch(on: OnionRequestAPI.workQueue) { error = $0; semaphore.signal() @@ -16,6 +16,39 @@ class OnionRequestAPITests : XCTestCase { XCTAssert(error == nil) } - // TODO: Add request sending test - // TODO: Add error handling test + /// Builds a path and then routes the same request through it several times. Logs the number of successes + /// versus the number of failures. + func testOnionRequestSending() { + let semaphore = DispatchSemaphore(value: 0) + LokiAPI.getRandomSnode().then(on: OnionRequestAPI.workQueue) { snode -> Promise in + return OnionRequestAPI.getPath().map(on: OnionRequestAPI.workQueue) { _ in snode } + }.done(on: OnionRequestAPI.workQueue) { snode in + var successCount = 0 + var failureCount = 0 + let promises: [Promise] = (0..<16).map { _ in + let mockSessionID = "0582bc30f11e8a9736407adcaca03b049f4acd4af3ae7eb6b6608d30f0b1e6a20e" + let parameters: JSON = [ "pubKey" : mockSessionID ] + let (promise, seal) = Promise.pending() + OnionRequestAPI.invoke(.getSwarm, on: snode, with: parameters).done(on: OnionRequestAPI.workQueue) { _ in + successCount += 1 + seal.fulfill(()) + }.catch(on: OnionRequestAPI.workQueue) { error in + failureCount += 1 + seal.reject(error) + }.finally(on: OnionRequestAPI.workQueue) { + print("[Loki] [Onion Request API] Success rate: \(successCount)/\(failureCount).") + } + return promise + } + when(resolved: promises).done(on: OnionRequestAPI.workQueue) { _ in + semaphore.signal() + } + }.catch(on: OnionRequestAPI.workQueue) { error in + print("[Loki] [Onion Request API] Path building failed due to error: \(error).") + semaphore.signal() + } + semaphore.wait() + } + + // TODO: Test error handling }