From 23b7b82a0a92aa2839cc239c0fbe9a34db5d3908 Mon Sep 17 00:00:00 2001 From: Dariusz Rybicki <dariusz@elixxir.io> Date: Wed, 28 Sep 2022 22:56:33 +0200 Subject: [PATCH] Add MessengerStop function wrapper --- .../Messenger/Functions/MessengerStop.swift | 60 +++++++++ .../Messenger/Messenger.swift | 3 + .../Functions/MessengerStopTests.swift | 123 ++++++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 Sources/XXMessengerClient/Messenger/Functions/MessengerStop.swift create mode 100644 Tests/XXMessengerClientTests/Messenger/Functions/MessengerStopTests.swift diff --git a/Sources/XXMessengerClient/Messenger/Functions/MessengerStop.swift b/Sources/XXMessengerClient/Messenger/Functions/MessengerStop.swift new file mode 100644 index 00000000..6e49054f --- /dev/null +++ b/Sources/XXMessengerClient/Messenger/Functions/MessengerStop.swift @@ -0,0 +1,60 @@ +import Foundation +import XCTestDynamicOverlay +import XXClient + +public struct MessengerStop { + public struct Wait: Equatable { + public init( + sleepInterval: TimeInterval = 1, + retries: Int = 10 + ) { + self.sleepInterval = sleepInterval + self.retries = retries + } + + public var sleepInterval: TimeInterval + public var retries: Int + } + + public enum Error: Swift.Error { + case notLoaded + case timedOut + } + + public var run: (Wait?) throws -> Void + + public func callAsFunction(wait: Wait? = nil) throws -> Void { + try run(wait) + } +} + +extension MessengerStop { + public static func live(_ env: MessengerEnvironment) -> MessengerStop { + MessengerStop { wait in + guard let cMix = env.cMix() else { + throw Error.notLoaded + } + guard cMix.networkFollowerStatus() == .running else { + return + } + try cMix.stopNetworkFollower() + guard let wait else { return } + var retries = wait.retries + var hasRunningProcesses = cMix.hasRunningProcesses() + while retries > 0 && hasRunningProcesses { + env.sleep(wait.sleepInterval) + hasRunningProcesses = cMix.hasRunningProcesses() + retries -= 1 + } + if hasRunningProcesses { + throw Error.timedOut + } + } + } +} + +extension MessengerStop { + public static let unimplemented = MessengerStop( + run: XCTUnimplemented("\(Self.self)") + ) +} diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift index ce598c54..41c61329 100644 --- a/Sources/XXMessengerClient/Messenger/Messenger.swift +++ b/Sources/XXMessengerClient/Messenger/Messenger.swift @@ -13,6 +13,7 @@ public struct Messenger { public var registerAuthCallbacks: MessengerRegisterAuthCallbacks public var registerMessageListener: MessengerRegisterMessageListener public var start: MessengerStart + public var stop: MessengerStop public var isConnected: MessengerIsConnected public var connect: MessengerConnect public var isListeningForMessages: MessengerIsListeningForMessages @@ -53,6 +54,7 @@ extension Messenger { registerAuthCallbacks: .live(env), registerMessageListener: .live(env), start: .live(env), + stop: .live(env), isConnected: .live(env), connect: .live(env), isListeningForMessages: .live(env), @@ -94,6 +96,7 @@ extension Messenger { registerAuthCallbacks: .unimplemented, registerMessageListener: .unimplemented, start: .unimplemented, + stop: .unimplemented, isConnected: .unimplemented, connect: .unimplemented, isListeningForMessages: .unimplemented, diff --git a/Tests/XXMessengerClientTests/Messenger/Functions/MessengerStopTests.swift b/Tests/XXMessengerClientTests/Messenger/Functions/MessengerStopTests.swift new file mode 100644 index 00000000..e9cfd928 --- /dev/null +++ b/Tests/XXMessengerClientTests/Messenger/Functions/MessengerStopTests.swift @@ -0,0 +1,123 @@ +import CustomDump +import XCTest +import XXClient +@testable import XXMessengerClient + +final class MessengerStopTests: XCTestCase { + func testStop() throws { + var didStopNetworkFollower = 0 + + var env: MessengerEnvironment = .unimplemented + env.cMix.get = { + var cMix: CMix = .unimplemented + cMix.networkFollowerStatus.run = { .running } + cMix.stopNetworkFollower.run = { didStopNetworkFollower += 1 } + return cMix + } + let stop: MessengerStop = .live(env) + + try stop() + + XCTAssertNoDifference(didStopNetworkFollower, 1) + } + + func testStopWhenNotLoaded() { + var env: MessengerEnvironment = .unimplemented + env.cMix.get = { nil } + let stop: MessengerStop = .live(env) + + XCTAssertThrowsError(try stop()) { error in + XCTAssertNoDifference( + error as NSError, + MessengerStop.Error.notLoaded as NSError + ) + } + } + + func testStopWhenNotRunning() throws { + var env: MessengerEnvironment = .unimplemented + env.cMix.get = { + var cMix: CMix = .unimplemented + cMix.networkFollowerStatus.run = { .stopped } + return cMix + } + let stop: MessengerStop = .live(env) + + try stop() + } + + func testStopFailure() { + struct Failure: Error {} + let failure = Failure() + + var env: MessengerEnvironment = .unimplemented + env.cMix.get = { + var cMix: CMix = .unimplemented + cMix.networkFollowerStatus.run = { .running } + cMix.stopNetworkFollower.run = { throw failure } + return cMix + } + let stop: MessengerStop = .live(env) + + XCTAssertThrowsError(try stop()) { error in + XCTAssertNoDifference( + error as NSError, + failure as NSError + ) + } + } + + func testStopAndWait() throws { + var hasRunningProcesses: [Bool] = [true, true, false] + var didStopNetworkFollower = 0 + var didSleep: [TimeInterval] = [] + + var env: MessengerEnvironment = .unimplemented + env.cMix.get = { + var cMix: CMix = .unimplemented + cMix.networkFollowerStatus.run = { .running } + cMix.stopNetworkFollower.run = { didStopNetworkFollower += 1 } + cMix.hasRunningProcesses.run = { hasRunningProcesses.removeFirst() } + return cMix + } + env.sleep = { didSleep.append($0) } + let stop: MessengerStop = .live(env) + + try stop(wait: .init(sleepInterval: 123, retries: 3)) + + XCTAssertNoDifference(didStopNetworkFollower, 1) + XCTAssertNoDifference(didSleep, [123, 123]) + } + + func testStopAndWaitTimeout() { + var hasRunningProcesses: [Bool] = [true, true, true, true] + var didStopNetworkFollower = 0 + var didSleep: [TimeInterval] = [] + + var env: MessengerEnvironment = .unimplemented + env.cMix.get = { + var cMix: CMix = .unimplemented + cMix.networkFollowerStatus.run = { .running } + cMix.stopNetworkFollower.run = { didStopNetworkFollower += 1 } + cMix.hasRunningProcesses.run = { hasRunningProcesses.removeFirst() } + return cMix + } + env.sleep = { didSleep.append($0) } + let stop: MessengerStop = .live(env) + + XCTAssertThrowsError( + try stop(wait: .init( + sleepInterval: 123, + retries: 3 + )) + ) { error in + XCTAssertNoDifference( + error as NSError, + MessengerStop.Error.timedOut as NSError + ) + } + + XCTAssertNoDifference(didStopNetworkFollower, 1) + XCTAssertNoDifference(didSleep, [123, 123, 123]) + } +} -- GitLab