CarbStoreHKQueryTests.swift 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. //
  2. // CarbStoreHKQueryTests.swift
  3. // LoopKitHostedTests
  4. //
  5. // Created by Darin Krauss on 10/9/20.
  6. // Copyright © 2020 LoopKit Authors. All rights reserved.
  7. //
  8. import XCTest
  9. import HealthKit
  10. @testable import LoopKit
  11. class CarbStoreHKQueryTestsBase: PersistenceControllerTestCase {
  12. var healthStore: HKHealthStoreMock!
  13. var carbStore: CarbStore!
  14. var authorizationStatus: HKAuthorizationStatus = .notDetermined
  15. override func setUp() {
  16. super.setUp()
  17. healthStore = HKHealthStoreMock()
  18. healthStore.authorizationStatus = authorizationStatus
  19. carbStore = CarbStore(healthStore: healthStore,
  20. cacheStore: cacheStore,
  21. cacheLength: .hours(24),
  22. defaultAbsorptionTimes: (fast: .minutes(30), medium: .hours(3), slow: .hours(5)),
  23. observationInterval: .hours(1),
  24. provenanceIdentifier: Bundle.main.bundleIdentifier!)
  25. let semaphore = DispatchSemaphore(value: 0)
  26. cacheStore.onReady { (error) in
  27. semaphore.signal()
  28. }
  29. semaphore.wait()
  30. }
  31. override func tearDown() {
  32. carbStore = nil
  33. healthStore = nil
  34. super.tearDown()
  35. }
  36. }
  37. class CarbStoreHKQueryTestsAuthorized: CarbStoreHKQueryTestsBase {
  38. override func setUp() {
  39. authorizationStatus = .sharingAuthorized
  40. super.setUp()
  41. }
  42. func testObserverQueryStartup() {
  43. // Check that an observer query is registered when authorization is already determined.
  44. XCTAssertFalse(carbStore.authorizationRequired);
  45. let observerQueryCreated = expectation(description: "observer query created")
  46. carbStore.createObserverQuery = { (sampleType, predicate, updateHandler) -> HKObserverQuery in
  47. let observerQuery = HKObserverQueryMock(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler)
  48. observerQueryCreated.fulfill()
  49. return observerQuery
  50. }
  51. waitForExpectations(timeout: 2)
  52. }
  53. }
  54. class CarbStoreHKQueryTests: CarbStoreHKQueryTestsBase {
  55. func testHKQueryAnchorPersistence() {
  56. var observerQuery: HKObserverQueryMock? = nil
  57. var anchoredObjectQuery: HKAnchoredObjectQueryMock? = nil
  58. XCTAssert(carbStore.authorizationRequired);
  59. XCTAssertNil(carbStore.observerQuery);
  60. let observerQueryCreated = expectation(description: "observer query created")
  61. carbStore.createObserverQuery = { (sampleType, predicate, updateHandler) -> HKObserverQuery in
  62. observerQuery = HKObserverQueryMock(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler)
  63. observerQueryCreated.fulfill()
  64. return observerQuery!
  65. }
  66. let authorizationCompletion = expectation(description: "authorization completion")
  67. carbStore.authorize { (result) in
  68. print(result)
  69. authorizationCompletion.fulfill()
  70. }
  71. waitForExpectations(timeout: 3)
  72. XCTAssertNotNil(observerQuery)
  73. let anchoredObjectQueryCreationExpectation = expectation(description: "anchored object query creation")
  74. carbStore.createAnchoredObjectQuery = { (sampleType, predicate, anchor, limit, resultsHandler) -> HKAnchoredObjectQuery in
  75. anchoredObjectQuery = HKAnchoredObjectQueryMock(type: sampleType, predicate: predicate, anchor: anchor, limit: limit, resultsHandler: resultsHandler)
  76. anchoredObjectQueryCreationExpectation.fulfill()
  77. return anchoredObjectQuery!
  78. }
  79. let observerQueryCompletionExpectation = expectation(description: "observer query completion")
  80. let observerQueryCompletionHandler = {
  81. observerQueryCompletionExpectation.fulfill()
  82. }
  83. // This simulates a signal marking the arrival of new HK Data.
  84. observerQuery!.updateHandler(observerQuery!, observerQueryCompletionHandler, nil)
  85. wait(for: [anchoredObjectQueryCreationExpectation], timeout: 3)
  86. // Trigger results handler for anchored object query
  87. let returnedAnchor = HKQueryAnchor(fromValue: 5)
  88. anchoredObjectQuery!.resultsHandler(anchoredObjectQuery!, [], [], returnedAnchor, nil)
  89. // Wait for observerQueryCompletionExpectation
  90. waitForExpectations(timeout: 3)
  91. XCTAssertNotNil(carbStore.queryAnchor)
  92. cacheStore.managedObjectContext.performAndWait {}
  93. // Create a new carb store, and ensure it uses the last query anchor
  94. let newCarbStore = CarbStore(healthStore: healthStore,
  95. cacheStore: cacheStore,
  96. cacheLength: .hours(24),
  97. defaultAbsorptionTimes: (fast: .minutes(30), medium: .hours(3), slow: .hours(5)),
  98. observationInterval: .hours(1),
  99. provenanceIdentifier: Bundle.main.bundleIdentifier!)
  100. observerQuery = nil
  101. let newObserverQueryCreated = expectation(description: "new observer query created")
  102. newCarbStore.createObserverQuery = { (sampleType, predicate, updateHandler) -> HKObserverQuery in
  103. observerQuery = HKObserverQueryMock(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler)
  104. newObserverQueryCreated.fulfill()
  105. return observerQuery!
  106. }
  107. let newAuthorizationCompletion = expectation(description: "authorization completion")
  108. newCarbStore.authorize { (result) in
  109. newAuthorizationCompletion.fulfill()
  110. }
  111. waitForExpectations(timeout: 3)
  112. anchoredObjectQuery = nil
  113. let newAnchoredObjectQueryCreationExpectation = expectation(description: "new anchored object query creation")
  114. newCarbStore.createAnchoredObjectQuery = { (sampleType, predicate, anchor, limit, resultsHandler) -> HKAnchoredObjectQuery in
  115. anchoredObjectQuery = HKAnchoredObjectQueryMock(type: sampleType, predicate: predicate, anchor: anchor, limit: limit, resultsHandler: resultsHandler)
  116. newAnchoredObjectQueryCreationExpectation.fulfill()
  117. return anchoredObjectQuery!
  118. }
  119. // This simulates a signal marking the arrival of new HK Data.
  120. observerQuery!.updateHandler(observerQuery!, {}, nil)
  121. wait(for: [newAnchoredObjectQueryCreationExpectation], timeout: 3)
  122. // Assert new carb store is querying with the last anchor that our HealthKit mock returned
  123. XCTAssertEqual(returnedAnchor, anchoredObjectQuery?.anchor)
  124. anchoredObjectQuery!.resultsHandler(anchoredObjectQuery!, [], [], returnedAnchor, nil)
  125. }
  126. }