Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for BulkUpload #2

Merged
merged 6 commits into from
Jan 8, 2025
Merged

Add tests for BulkUpload #2

merged 6 commits into from
Jan 8, 2025

Conversation

bryant-jimenez
Copy link
Collaborator

UI Testing for BulkUpload

♻️ Current situation & Problem

Link any open issues or pull requests (PRs) related to this PR. Please ensure that all non-trivial PRs are first tracked and discussed in an existing GitHub issue or discussion.

⚙️ Release Notes

Add a bullet point list summary of the feature and possible migration guides if this is a breaking change so this section can be added to the release notes.
Include code snippets that provide examples of the feature implemented or links to the documentation if it appends or changes the public interface.

📚 Documentation

Please ensure that you properly document any additions in conformance to Spezi Documentation Guide.
You can use this section to describe your solution, but we encourage contributors to document your reasoning and changes using in-line documentation.

✅ Testing

Please ensure that the PR meets the testing requirements set by CodeCov and that new functionality is appropriately tested.
This section describes important information about the tests and why some elements might not be testable.

📝 Code of Conduct & Contributing Guidelines

By submitting creating this pull request, you agree to follow our Code of Conduct and Contributing Guidelines:

Copy link
Owner

@mjoerke mjoerke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding the test cases! Mostly looks good but there are some small things I left comments on

Sources/SpeziHealthKit/BulkUploadConstraint.swift Outdated Show resolved Hide resolved
HKObjectType.quantityType(forIdentifier: .stepCount)!,
HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!
]
try await healthStore.requestAuthorization(toShare: toShareSampleTypes, read: healthKitSampleTypes)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot hard code the sample types here – this will request authorization to share step count and active energy burned in all applications that use SpeziHealthKit. We should figure out a way to add this in the UI test application, I think you should just be able to call
healthStore.requestAuthorization(toShare: toShareSampleTypes, read: healthKitSampleTypes)
again and it will ask for the updated share permissions

Copy link
Collaborator Author

@bryant-jimenez bryant-jimenez Apr 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching this - definitely don't want that to be the case for all users of SpeziHealthKit. The health store is unfortunately a private variable inside of the healthkit module, so I can't access it directly to call requestAuthorization and pass in the types to share.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a bit of a hack, but are you able to just initialize and access your own HKHealthStore object from within the UI test app? I just don't think adding additional permissions to the entire SpeziHealthKit package is feasible. The alternative would be to add functionality to SpeziHealthKit that allows you to declare types you want to share (in addition to read permissions)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PSchmiedmayer Hi Paul, right now we're running into issues in the test app with getting write permissions to inject step count data for testing purposes. I have the button that injects data, but has to do so with a separate instance of the apple HealthStore, since SpeziHealthKit currently doesn't support passing in types to request write access (only read).

The issue with this is that now the health authorization sheet pops up when triggering manual data collection in the test app, which shouldn't be the case, but this separate instance is necessary because of the private protection levels in the HealthKit module for the sample types passed in to healthStore.requestAuthorization().

I had originally modified SpeziHealthKit directly (unknowingly) but pivoted (as @mjoerke suggested above) and attempted this separate HKStore instance to try to get around it. With the modifications to SpeziHealthKit (hardcoded but it showed that it could work), the tests successfully passed regarding bulkupload, but we obviously can't leave those hardcoded write permissions in.

Recognizing the time crunch we're on with starting internal user studies this week, we wanted some guidance on how to go about this since it feels like we're spending time "hacking" the test app. Given the time crunch with internal user studies starting this week, we felt it might be best to start integrating within the Prisma app. Eventually it might be good to have SpeziHealthKit allow for some write permissions as well so that we can use them for the test app, but we did want to get moving on integrating within Prisma.

Would love your thoughts/input on this! 🙏🏽

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bryant-jimenez I would suggest to manually request permissions to get write permissions when you press the button to inject the data. You can do all the operations in an async function based on the button press (e.g. how to get write permissions: https://developer.apple.com/documentation/healthkit/authorizing_access_to_health_data) and within your UI test use the same UI testing code that we use to handle and dismiss the HealthKit permissions sheet ... that might be the cleanest way to handle this 🚀

return
}
let HKStore = HKHealthStore()
let startDate = Date()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand this correctly, it's injected 500 step count samples that start now and end 5 minutes from now.

Why does this get triggered in the bulk upload if it is fetching historical data from 6 months ago up until the time the app was first launched?

Set([HKQuantityType(.stepCount)]),
predicate: HKQuery.predicateForSamples(
withStart: Calendar.current.date(byAdding: .month, value: -6, to: .now),
end: nil,
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re the previous comment about the BulkUpload triggering, I'm not 100% about how end: nil is interpreted, but we might want to have the query end with Date() such that we don't double count samples?

Couldn't find an answer in the documentation but it might mean the predicate includes all incoming samples in the future?

Copy link
Collaborator Author

@bryant-jimenez bryant-jimenez Apr 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im actually not too sure about this either, but your point makes sense - these shouldnt be collected based on the current predicate. This is the answer I got from GPT:

The provided query predicate is interpreted as follows:

  • HKQuery.predicateForSamples(withStart:end:options:) is a method used to create a predicate for querying HealthKit samples within a specific time range.
  • In this case:
    • withStart parameter specifies the start date of the query's time range. It is calculated by subtracting 6 months from the current date using Calendar.current.date(byAdding: .month, value: -6, to: .now).
    • end parameter is set to nil, indicating that there is no end date specified, meaning the query will continue to the current time.
    • options parameter is set to .strictEndDate, which specifies that the end date is exclusive, meaning samples collected exactly at the end date will not be included in the query results.

So, the predicate will retrieve HealthKit samples collected within the last 6 months up to the current moment, excluding any samples collected exactly at the current time.

Would it be possible that since the samples are uploaded milliseconds (or a very very short time) before the query starts executing, they're still being collected? And since end is nil, it includes these since its technically not the current time?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think specifying Date() should fix it, will give it a try and also modify the samples that I inject

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for looking into this – not sure I trust GPT's answer 100% since the answer is sparsely documented on the internet, but it could be true. I think it's a good idea for the BulkUpload to end at Date() either way, both in this test app and our Prisma app, since that clear specifies which samples belong in BulkUpload vs CollectSamples

@@ -14,22 +14,25 @@ import SwiftUI
struct HealthKitTestsView: View {
@Environment(HealthKit.self) var healthKitModule
@Environment(HealthKitStore.self) var healthKitStore


var body: some View {
List {
AsyncButton("Ask for authorization") {
try? await healthKitModule.askForAuthorization()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will probably have to add the toShare types here when you request authorization

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re other comment about accessing healthstore

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants