From b63f86c406fca9b9df3604ebb1b337bf60a3f8b3 Mon Sep 17 00:00:00 2001
From: Dariusz Rybicki <dariusz@elixxir.io>
Date: Tue, 8 Nov 2022 11:29:25 +0100
Subject: [PATCH] Add MessengerTrackServices

---
 .../Functions/MessengerTrackServices.swift    | 42 ++++++++++++
 .../Messenger/Messenger.swift                 |  7 +-
 .../Messenger/MessengerEnvironment.swift      |  3 +
 .../MessengerTrackServicesTests.swift         | 64 +++++++++++++++++++
 .../TestHelpers/TestDoubles.swift             | 25 ++++++++
 5 files changed, 139 insertions(+), 2 deletions(-)
 create mode 100644 Sources/XXMessengerClient/Messenger/Functions/MessengerTrackServices.swift
 create mode 100644 Tests/XXMessengerClientTests/Messenger/Functions/MessengerTrackServicesTests.swift

diff --git a/Sources/XXMessengerClient/Messenger/Functions/MessengerTrackServices.swift b/Sources/XXMessengerClient/Messenger/Functions/MessengerTrackServices.swift
new file mode 100644
index 00000000..45dfc644
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functions/MessengerTrackServices.swift
@@ -0,0 +1,42 @@
+import XCTestDynamicOverlay
+import XXClient
+
+public struct MessengerTrackServices {
+  public enum Error: Swift.Error, Equatable {
+    case notLoaded
+  }
+
+  public typealias OnError = (Swift.Error) -> Void
+
+  public var run: (@escaping OnError) throws -> Void
+
+  public func callAsFunction(onError: @escaping OnError) throws {
+    try run(onError)
+  }
+}
+
+extension MessengerTrackServices {
+  public static func live(_ env: MessengerEnvironment) -> MessengerTrackServices {
+    MessengerTrackServices { onError in
+      guard let cMix = env.cMix() else {
+        throw Error.notLoaded
+      }
+      let callback = TrackServicesCallback { result in
+        switch result {
+        case .success(let serviceList):
+          env.serviceList.set(serviceList)
+        case .failure(let error):
+          env.serviceList.set(nil)
+          onError(error)
+        }
+      }
+      cMix.trackServices(callback: callback)
+    }
+  }
+}
+
+extension MessengerTrackServices {
+  public static let unimplemented = MessengerTrackServices(
+    run: XCTUnimplemented("\(Self.self)")
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift
index a6f1ee0d..12a036eb 100644
--- a/Sources/XXMessengerClient/Messenger/Messenger.swift
+++ b/Sources/XXMessengerClient/Messenger/Messenger.swift
@@ -46,6 +46,7 @@ public struct Messenger {
   public var startFileTransfer: MessengerStartFileTransfer
   public var sendFile: MessengerSendFile
   public var receiveFile: MessengerReceiveFile
+  public var trackServices: MessengerTrackServices
 }
 
 extension Messenger {
@@ -95,7 +96,8 @@ extension Messenger {
       isFileTransferRunning: .live(env),
       startFileTransfer: .live(env),
       sendFile: .live(env),
-      receiveFile: .live(env)
+      receiveFile: .live(env),
+      trackServices: .live(env)
     )
   }
 }
@@ -146,6 +148,7 @@ extension Messenger {
     isFileTransferRunning: .unimplemented,
     startFileTransfer: .unimplemented,
     sendFile: .unimplemented,
-    receiveFile: .unimplemented
+    receiveFile: .unimplemented,
+    trackServices: .unimplemented
   )
 }
diff --git a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
index a1ab1517..d8c68787 100644
--- a/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
+++ b/Sources/XXMessengerClient/Messenger/MessengerEnvironment.swift
@@ -38,6 +38,7 @@ public struct MessengerEnvironment {
   public var registerLogWriter: RegisterLogWriter
   public var resumeBackup: ResumeBackup
   public var searchUD: SearchUD
+  public var serviceList: Stored<MessageServiceList?>
   public var setLogLevel: SetLogLevel
   public var sleep: (TimeInterval) -> Void
   public var storageDir: String
@@ -89,6 +90,7 @@ extension MessengerEnvironment {
       registerLogWriter: .live,
       resumeBackup: .live,
       searchUD: .live,
+      serviceList: .inMemory(),
       setLogLevel: .live,
       sleep: { Thread.sleep(forTimeInterval: $0) },
       storageDir: MessengerEnvironment.defaultStorageDir,
@@ -135,6 +137,7 @@ extension MessengerEnvironment {
     registerLogWriter: .unimplemented,
     resumeBackup: .unimplemented,
     searchUD: .unimplemented,
+    serviceList: .unimplemented(),
     setLogLevel: .unimplemented,
     sleep: XCTUnimplemented("\(Self.self).sleep"),
     storageDir: "unimplemented",
diff --git a/Tests/XXMessengerClientTests/Messenger/Functions/MessengerTrackServicesTests.swift b/Tests/XXMessengerClientTests/Messenger/Functions/MessengerTrackServicesTests.swift
new file mode 100644
index 00000000..557832e3
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functions/MessengerTrackServicesTests.swift
@@ -0,0 +1,64 @@
+import CustomDump
+import XCTest
+import XCTestDynamicOverlay
+import XXClient
+@testable import XXMessengerClient
+
+final class MessengerTrackServicesTests: XCTestCase {
+  func testTrack() throws {
+    struct Failure: Error, Equatable {}
+    let failure = Failure()
+    let serviceList = MessageServiceList.stub()
+
+    var didSetServiceList: [MessageServiceList?] = []
+    var didReceiveError: [Error] = []
+    var callbacks: [TrackServicesCallback] = []
+
+    var env: MessengerEnvironment = .unimplemented
+    env.serviceList.set = { serviceList in
+      didSetServiceList.append(serviceList)
+    }
+    env.cMix.get = {
+      var cMix: CMix = .unimplemented
+      cMix.trackServices.run = { callback in
+        callbacks.append(callback)
+      }
+      return cMix
+    }
+    let track: MessengerTrackServices = .live(env)
+
+    try track(onError: { error in
+      didReceiveError.append(error)
+    })
+
+    XCTAssertEqual(callbacks.count, 1)
+
+    didSetServiceList = []
+    didReceiveError = []
+    callbacks.first?.handle(.success(serviceList))
+
+    XCTAssertNoDifference(didSetServiceList, [serviceList])
+    XCTAssertEqual(didReceiveError.count, 0)
+
+    didSetServiceList = []
+    didReceiveError = []
+    callbacks.first?.handle(.failure(failure))
+
+    XCTAssertNoDifference(didSetServiceList, [nil])
+    XCTAssertEqual(didReceiveError.count, 1)
+    XCTAssertNoDifference(didReceiveError.first as? Failure, failure)
+  }
+
+  func testTrackWhenNotLoaded() {
+    var env: MessengerEnvironment = .unimplemented
+    env.cMix.get = { nil }
+    let track: MessengerTrackServices = .live(env)
+
+    XCTAssertThrowsError(try track(onError: unimplemented())) { error in
+      XCTAssertNoDifference(
+        error as NSError,
+        MessengerTrackServices.Error.notLoaded as NSError
+      )
+    }
+  }
+}
diff --git a/Tests/XXMessengerClientTests/TestHelpers/TestDoubles.swift b/Tests/XXMessengerClientTests/TestHelpers/TestDoubles.swift
index e43d76ac..d36ad479 100644
--- a/Tests/XXMessengerClientTests/TestHelpers/TestDoubles.swift
+++ b/Tests/XXMessengerClientTests/TestHelpers/TestDoubles.swift
@@ -30,3 +30,28 @@ extension ReceivedFile {
     )
   }
 }
+
+extension MessageServiceList {
+  static func stub() -> MessageServiceList {
+    (1...3).map { .stub($0) }
+  }
+}
+
+extension MessageServiceListElement {
+  static func stub(_ id: Int) -> MessageServiceListElement {
+    MessageServiceListElement(
+      id: "id-\(id)".data(using: .utf8)!,
+      services: (1...3).map { $0 + 10 * id }.map { .stub($0) }
+    )
+  }
+}
+
+extension MessageService {
+  static func stub(_ id: Int) -> MessageService {
+    MessageService(
+      identifier: "identifier-\(id)".data(using: .utf8)!,
+      tag: "tag-\(id)",
+      metadata: "metadata-\(id)".data(using: .utf8)!
+    )
+  }
+}
-- 
GitLab