MockService.swift 6.0 KB

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