CarbStoreHKQueryTests.swift 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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 was registered even before authorize() is called.
  44. XCTAssertFalse(carbStore.authorizationRequired);
  45. XCTAssertNotNil(carbStore.observerQuery);
  46. }
  47. }
  48. class CarbStoreHKQueryTests: CarbStoreHKQueryTestsBase {
  49. func testHKQueryAnchorPersistence() {
  50. var observerQuery: HKObserverQueryMock? = nil
  51. var anchoredObjectQuery: HKAnchoredObjectQueryMock? = nil
  52. XCTAssert(carbStore.authorizationRequired);
  53. XCTAssertNil(carbStore.observerQuery);
  54. carbStore.createObserverQuery = { (sampleType, predicate, updateHandler) -> HKObserverQuery in
  55. observerQuery = HKObserverQueryMock(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler)
  56. return observerQuery!
  57. }
  58. let authorizationCompletion = expectation(description: "authorization completion")
  59. carbStore.authorize { (result) in
  60. print(result)
  61. authorizationCompletion.fulfill()
  62. }
  63. waitForExpectations(timeout: 3)
  64. XCTAssertNotNil(observerQuery)
  65. let anchoredObjectQueryCreationExpectation = expectation(description: "anchored object query creation")
  66. carbStore.createAnchoredObjectQuery = { (sampleType, predicate, anchor, limit, resultsHandler) -> HKAnchoredObjectQuery in
  67. anchoredObjectQuery = HKAnchoredObjectQueryMock(type: sampleType, predicate: predicate, anchor: anchor, limit: limit, resultsHandler: resultsHandler)
  68. anchoredObjectQueryCreationExpectation.fulfill()
  69. return anchoredObjectQuery!
  70. }
  71. let observerQueryCompletionExpectation = expectation(description: "observer query completion")
  72. let observerQueryCompletionHandler = {
  73. observerQueryCompletionExpectation.fulfill()
  74. }
  75. // This simulates a signal marking the arrival of new HK Data.
  76. observerQuery!.updateHandler(observerQuery!, observerQueryCompletionHandler, nil)
  77. wait(for: [anchoredObjectQueryCreationExpectation], timeout: 3)
  78. // Trigger results handler for anchored object query
  79. let returnedAnchor = HKQueryAnchor(fromValue: 5)
  80. anchoredObjectQuery!.resultsHandler(anchoredObjectQuery!, [], [], returnedAnchor, nil)
  81. // Wait for observerQueryCompletionExpectation
  82. waitForExpectations(timeout: 3)
  83. XCTAssertNotNil(carbStore.queryAnchor)
  84. cacheStore.managedObjectContext.performAndWait {}
  85. // Create a new carb store, and ensure it uses the last query anchor
  86. let newCarbStore = CarbStore(healthStore: healthStore,
  87. cacheStore: cacheStore,
  88. cacheLength: .hours(24),
  89. defaultAbsorptionTimes: (fast: .minutes(30), medium: .hours(3), slow: .hours(5)),
  90. observationInterval: .hours(1),
  91. provenanceIdentifier: Bundle.main.bundleIdentifier!)
  92. let newAuthorizationCompletion = expectation(description: "authorization completion")
  93. observerQuery = nil
  94. newCarbStore.createObserverQuery = { (sampleType, predicate, updateHandler) -> HKObserverQuery in
  95. observerQuery = HKObserverQueryMock(sampleType: sampleType, predicate: predicate, updateHandler: updateHandler)
  96. return observerQuery!
  97. }
  98. newCarbStore.authorize { (result) in
  99. newAuthorizationCompletion.fulfill()
  100. }
  101. waitForExpectations(timeout: 3)
  102. anchoredObjectQuery = nil
  103. let newAnchoredObjectQueryCreationExpectation = expectation(description: "new anchored object query creation")
  104. newCarbStore.createAnchoredObjectQuery = { (sampleType, predicate, anchor, limit, resultsHandler) -> HKAnchoredObjectQuery in
  105. anchoredObjectQuery = HKAnchoredObjectQueryMock(type: sampleType, predicate: predicate, anchor: anchor, limit: limit, resultsHandler: resultsHandler)
  106. newAnchoredObjectQueryCreationExpectation.fulfill()
  107. return anchoredObjectQuery!
  108. }
  109. // This simulates a signal marking the arrival of new HK Data.
  110. observerQuery!.updateHandler(observerQuery!, {}, nil)
  111. wait(for: [newAnchoredObjectQueryCreationExpectation], timeout: 3)
  112. // Assert new carb store is querying with the last anchor that our HealthKit mock returned
  113. XCTAssertEqual(returnedAnchor, anchoredObjectQuery?.anchor)
  114. anchoredObjectQuery!.resultsHandler(anchoredObjectQuery!, [], [], returnedAnchor, nil)
  115. }
  116. }