MockService.swift 5.9 KB

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