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 Launch and Submission Timestamps to QR #2672

Open
wants to merge 11 commits into
base: master
Choose a base branch
from

Conversation

hamza-vd
Copy link

@hamza-vd hamza-vd commented Sep 12, 2024

IMPORTANT: All PRs must be linked to an issue (except for extremely trivial and straightforward changes).

Fixes #2372

Description
Clear and concise code change description.

Alternative(s) considered
Have you considered any alternatives? And if so, why have you chosen the approach in this PR?

Type
Choose one: (Bug fix | Feature | Documentation | Testing | Code health | Builds | Releases | Other)

Screenshots (if applicable)

Checklist

  • I have read and acknowledged the Code of conduct.
  • I have read the Contributing page.
  • I have signed the Google Individual CLA, or I am covered by my company's Corporate CLA.
  • I have discussed my proposed solution with code owners in the linked issue(s) and we have agreed upon the general approach.
  • I have run ./gradlew spotlessApply and ./gradlew spotlessCheck to check my code follows the style guide of this project.
  • I have run ./gradlew check and ./gradlew connectedCheck to test my changes locally.
  • I have built and run the demo app(s) to verify my change fixes the issue and/or does not break the demo app(s).

@@ -154,3 +159,21 @@ private fun unpackRepeatedGroups(
listOf(questionnaireResponseItem)
}
}

/** Adds a launch timestamp as an extension to the Questionnaire Response */
Copy link
Collaborator

Choose a reason for hiding this comment

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

can you clarify in the doc that we only add the launch timestamp if there isn't one at the moment?

Copy link
Collaborator

Choose a reason for hiding this comment

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

or should we make this extension repeated so that each time you edit the questionnaire response it is recorded.

useful for audit purposes?

Copy link
Collaborator

Choose a reason for hiding this comment

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

OR if we really want to only keep one (to be a bit more consistent with the authored fied) we can rename this extension to lastLaunched?

Copy link
Author

Choose a reason for hiding this comment

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

In my opinion, the lastLaunched will make more sense. cc: @qiarie

@ktarasenko ktarasenko removed their request for review September 17, 2024 14:04
Copy link
Collaborator

@jingtang10 jingtang10 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 creating this new pr @hamza-vd

a few small comments

.find { it.url == EXTENSION_LAST_LAUNCHED_TIMESTAMP }
?.let {
// Replace the existing extension with a new one having the updated value
this.extension[this.extension.indexOf(it)] =
Copy link
Collaborator

Choose a reason for hiding this comment

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

can we just overwrite the value here?

the whole operation of this this.extension[this.extension.indexOf(it)] seems to negate the benefit of using scope functions... looks a bit more clumsy in my opinion.

Copy link
Author

Choose a reason for hiding this comment

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

@jingtang10 this is because we need to keep the previous extensions intact and only update the url for a specific extension. The url in extension is a immutable property so I had to assign a new one.

Copy link
Collaborator

Choose a reason for hiding this comment

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

i mean can you just overwrite th value without changeing the url? the url is already the same (as it has been checked in line 174).

so do somethign like this.extension.setValue

Copy link
Author

Choose a reason for hiding this comment

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

Updated

@@ -183,8 +184,23 @@ class QuestionnaireViewModelParameterizedTest(
val printer: IParser = FhirContext.forR4().newJsonParser()

fun <T : IBaseResource> assertResourceEquals(actual: T, expected: T) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

as @ndegwamartin pointed out, might as well split this assert function into two to make it clearer and use the right one in the relevant tests...

i think at the moment this code might hide errors and make debugging difficult in the future.

Copy link
Author

@hamza-vd hamza-vd Oct 8, 2024

Choose a reason for hiding this comment

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

@ndegwamartin can you please elaborate further on how can we split the assertion here?

Copy link
Collaborator

Choose a reason for hiding this comment

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

create a new function to assert two questionnaire responses in which you fiddle with the timestamps.

this assertion is used by a lot of tests. seems at least inefficient to do this operation for all resource types.

Copy link
Author

@hamza-vd hamza-vd Oct 14, 2024

Choose a reason for hiding this comment

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

@jingtang10 @ndegwamartin cc: @qiarie

The updates I made to this method were not to test my own code, but to ensure the failing tests would pass. You can find the tests for my implementation here.

After adding timestamps to the QuestionnaireResponses, many tests that asserted response equality started failing due to mismatching timestamps. Although the difference was only in milliseconds, it still caused the checks to fail. This left me with two options:

  1. Update all the failing tests to use the same timestamp values for both launch and submission.
  2. Modify the assertion method to programmatically adjust the expected and actual response timestamps.

I chose the second approach as it was more time-efficient, and we already have separate tests for timestamp functionality. I hope this makes sense.

Copy link
Collaborator

Choose a reason for hiding this comment

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

The problem is that the function is now doing things that is quite specific to questionnaire responses and someone in the future is going to call the assertResouceEquals function and assume that it's just testing two resoures are equal but it's not... From a code health's perspective this is an anti pattern... we should make sure that the function does what the name suggests that it does.

Please create a function called assertQuestionnaireResponseEqualsIgnoringLaunchTimestamp which takes two QuestionnaireResponses. In the test cases that you are seeing that fail - they should use this new funciton instead of the old function assertResourceEquals.

I think this change shouldn't be too big - it should be easy to find and replace usage of this function with questionnaire responses and use the new funciton.

Copy link
Collaborator

Choose a reason for hiding this comment

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

also make sure you don't mutate the resources - make a copy and then remove the timestamp.

@@ -7514,8 +7515,23 @@ class QuestionnaireViewModelTest {
val printer: IParser = FhirContext.forR4().newJsonParser()

fun <T : IBaseResource> assertResourceEquals(actual: T, expected: T) {
assertThat(printer.encodeResourceToString(actual))
.isEqualTo(printer.encodeResourceToString(expected))
if (actual is QuestionnaireResponse && expected is QuestionnaireResponse) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

same here.

.find { it.url == EXTENSION_LAST_LAUNCHED_TIMESTAMP }
?.let {
// Replace the existing extension with a new one having the updated value
this.extension[this.extension.indexOf(it)] =
Copy link
Collaborator

Choose a reason for hiding this comment

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

i mean can you just overwrite th value without changeing the url? the url is already the same (as it has been checked in line 174).

so do somethign like this.extension.setValue

@@ -183,8 +184,23 @@ class QuestionnaireViewModelParameterizedTest(
val printer: IParser = FhirContext.forR4().newJsonParser()

fun <T : IBaseResource> assertResourceEquals(actual: T, expected: T) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

create a new function to assert two questionnaire responses in which you fiddle with the timestamps.

this assertion is used by a lot of tests. seems at least inefficient to do this operation for all resource types.

@@ -183,8 +184,23 @@ class QuestionnaireViewModelParameterizedTest(
val printer: IParser = FhirContext.forR4().newJsonParser()

fun <T : IBaseResource> assertResourceEquals(actual: T, expected: T) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

The problem is that the function is now doing things that is quite specific to questionnaire responses and someone in the future is going to call the assertResouceEquals function and assume that it's just testing two resoures are equal but it's not... From a code health's perspective this is an anti pattern... we should make sure that the function does what the name suggests that it does.

Please create a function called assertQuestionnaireResponseEqualsIgnoringLaunchTimestamp which takes two QuestionnaireResponses. In the test cases that you are seeing that fail - they should use this new funciton instead of the old function assertResourceEquals.

I think this change shouldn't be too big - it should be easy to find and replace usage of this function with questionnaire responses and use the new funciton.

@@ -183,8 +184,23 @@ class QuestionnaireViewModelParameterizedTest(
val printer: IParser = FhirContext.forR4().newJsonParser()

fun <T : IBaseResource> assertResourceEquals(actual: T, expected: T) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

also make sure you don't mutate the resources - make a copy and then remove the timestamp.

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

Successfully merging this pull request may close these issues.

Ability to Capture Questionnaire Launch and Submit Timestamps
3 participants