MockService.swift 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. //
  2. // MockService.swift
  3. // MockKit
  4. //
  5. // Created by Darin Krauss on 5/17/19.
  6. // Copyright © 2019 LoopKit Authors. All rights reserved.
  7. //
  8. import os.log
  9. import Foundation
  10. import LoopKit
  11. public final class MockService: Service {
  12. public static let pluginIdentifier = "MockService"
  13. public static let localizedTitle = "Simulator"
  14. public weak var stateDelegate: StatefulPluggableDelegate?
  15. public weak var serviceDelegate: ServiceDelegate?
  16. public var remoteData: Bool
  17. public var logging: Bool
  18. public var analytics: Bool
  19. public let maxHistoryItems = 1000
  20. private var lockedHistory = Locked<[String]>([])
  21. public var history: [String] {
  22. lockedHistory.value
  23. }
  24. private var dateFormatter = ISO8601DateFormatter()
  25. public init() {
  26. self.remoteData = true
  27. self.logging = true
  28. self.analytics = true
  29. }
  30. public init?(rawState: RawStateValue) {
  31. self.remoteData = rawState["remoteData"] as? Bool ?? false
  32. self.logging = rawState["logging"] as? Bool ?? false
  33. self.analytics = rawState["analytics"] as? Bool ?? false
  34. }
  35. public var rawState: RawStateValue {
  36. var rawValue: RawStateValue = [:]
  37. rawValue["remoteData"] = remoteData
  38. rawValue["logging"] = logging
  39. rawValue["analytics"] = analytics
  40. return rawValue
  41. }
  42. public let isOnboarded = true // No distinction between created and onboarded
  43. public func completeCreate() {}
  44. public func completeUpdate() {
  45. stateDelegate?.pluginDidUpdateState(self)
  46. }
  47. public func completeDelete() {
  48. stateDelegate?.pluginWantsDeletion(self)
  49. }
  50. public func clearHistory() {
  51. lockedHistory.value = []
  52. }
  53. private func record(_ message: String) {
  54. let timestamp = self.dateFormatter.string(from: Date())
  55. lockedHistory.mutate { history in
  56. history.append("\(timestamp): \(message)")
  57. if history.count > self.maxHistoryItems {
  58. history.removeFirst(history.count - self.maxHistoryItems)
  59. }
  60. }
  61. }
  62. }
  63. extension MockService: AnalyticsService {
  64. public func recordIdentify(_ property: String, array: [String]) {
  65. record("[AnalyticsService] Identify: \(property) \(array)")
  66. }
  67. public func recordAnalyticsEvent(_ name: String, withProperties properties: [AnyHashable: Any]?, outOfSession: Bool) {
  68. if analytics {
  69. record("[AnalyticsService] \(name) \(String(describing: properties)) \(outOfSession)")
  70. }
  71. }
  72. public func recordIdentify(_ property: String, value: String) {
  73. record("[AnalyticsService] Identify: \(property) \(value)")
  74. }
  75. }
  76. extension MockService: LoggingService {
  77. public func log(_ message: StaticString, subsystem: String, category: String, type: OSLogType, _ args: [CVarArg]) {
  78. if logging {
  79. // Since this is only stored in memory, do not worry about public/private qualifiers
  80. let messageWithoutQualifiers = message.description.replacingOccurrences(of: "%{public}", with: "%").replacingOccurrences(of: "%{private}", with: "%")
  81. let messageWithArguments = String(format: messageWithoutQualifiers, arguments: args)
  82. record("[LoggingService] \(messageWithArguments)")
  83. }
  84. }
  85. }
  86. extension MockService: RemoteDataService {
  87. public func uploadTemporaryOverrideData(updated: [TemporaryScheduleOverride], deleted: [TemporaryScheduleOverride], completion: @escaping (Result<Bool, Error>) -> Void) {
  88. if remoteData {
  89. record("[RemoteDataService] Upload temporary override data (updated: \(updated.count), deleted: \(deleted.count))")
  90. }
  91. completion(.success(false))
  92. }
  93. public func uploadAlertData(_ stored: [SyncAlertObject], completion: @escaping (Result<Bool, Error>) -> Void) {
  94. if remoteData {
  95. record("[RemoteDataService] Upload alert data (stored: \(stored.count))")
  96. }
  97. completion(.success(false))
  98. }
  99. public func uploadCarbData(created: [SyncCarbObject], updated: [SyncCarbObject], deleted: [SyncCarbObject], completion: @escaping (Result<Bool, Error>) -> Void) {
  100. if remoteData {
  101. record("[RemoteDataService] Upload carb data (created: \(created.count), updated: \(updated.count), deleted: \(deleted.count))")
  102. }
  103. completion(.success(false))
  104. }
  105. public func uploadDoseData(created: [DoseEntry], deleted: [DoseEntry], completion: @escaping (_ result: Result<Bool, Error>) -> Void) {
  106. if remoteData {
  107. record("[RemoteDataService] Upload dose data (created: \(created.count), deleted: \(deleted.count))")
  108. }
  109. completion(.success(false))
  110. }
  111. public func uploadDosingDecisionData(_ stored: [StoredDosingDecision], completion: @escaping (Result<Bool, Error>) -> Void) {
  112. if remoteData {
  113. let warned = stored.filter { !$0.warnings.isEmpty }
  114. let errored = stored.filter { !$0.errors.isEmpty }
  115. record("[RemoteDataService] Upload dosing decision data (stored: \(stored.count), warned: \(warned.count), errored: \(errored.count))")
  116. }
  117. completion(.success(false))
  118. }
  119. public func uploadGlucoseData(_ stored: [StoredGlucoseSample], completion: @escaping (Result<Bool, Error>) -> Void) {
  120. if remoteData {
  121. record("[RemoteDataService] Upload glucose data (stored: \(stored.count))")
  122. }
  123. completion(.success(false))
  124. }
  125. public func uploadPumpEventData(_ stored: [PersistedPumpEvent], completion: @escaping (Result<Bool, Error>) -> Void) {
  126. if remoteData {
  127. record("[RemoteDataService] Upload pump event data (stored: \(stored.count))")
  128. }
  129. completion(.success(false))
  130. }
  131. public func uploadSettingsData(_ stored: [StoredSettings], completion: @escaping (Result<Bool, Error>) -> Void) {
  132. if remoteData {
  133. record("[RemoteDataService] Upload settings data (stored: \(stored.count))")
  134. }
  135. completion(.success(false))
  136. }
  137. public func uploadCgmEventData(_ stored: [LoopKit.PersistedCgmEvent], completion: @escaping (Result<Bool, Error>) -> Void) {
  138. if remoteData {
  139. record("[RemoteDataService] Upload cgm event data (stored: \(stored.count))")
  140. }
  141. completion(.success(false))
  142. }
  143. public func remoteNotificationWasReceived(_ notification: [String: AnyObject]) async throws {
  144. }
  145. }