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 additionalSpecifications field to DeviceRegistration #484

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from

Conversation

yuanchen233
Copy link
Collaborator

As discussed in #431, adding a additionalSpecifications field to DeviceRegistration. This allows to keep additional specification data when register device and access them later on in StudyDeploymentStatus.deviceStatusList

@yuanchen233 yuanchen233 force-pushed the extra-information-for-device-registration branch 2 times, most recently from a9db9bd to 7f1572f Compare September 26, 2024 11:17
@yuanchen233
Copy link
Collaborator Author

For DeviceRegistrationTest, original test cases were kept to cover situations when additionalSpecifications is null; same for GenerateExampleRequests for rpc, additionalSpecifications is only added to one of the deviceRegistration.

@yuanchen233 yuanchen233 marked this pull request as ready for review September 27, 2024 16:18
TypeScript serialization wrapper for kotlinx serialization had to be updated since the addition of this field somehow seems to have resulted in different compiled method names.
@Whathecode Whathecode force-pushed the extra-information-for-device-registration branch from 0b57685 to 4c78321 Compare September 30, 2024 19:26
Copy link
Member

@Whathecode Whathecode left a comment

Choose a reason for hiding this comment

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

See comments; I already fixed those (you can resolve them after reading them).

In addition, I squashed three of the commits into one. Each commit ideally should pass all tests/be a cohesive whole. The last commit was a correct separate commit. 👍 I hope/presume you didn't have other changes on this branch, so I force pushed. Apologies if you did (as that can cause conflicts). Make sure to use git pull --rebase.

But, I see two other concerns before this can be merged:

  • I don't recall 100% whether or not we need @Required on the field. I vaguely remember it may be needed for some scenario, maybe "unknown polymorphic serialization". I need to dig up some old issues/documentation.
  • You didn't test whether additionalSpecification actually gets serialized as a JSON object (instead as a string with escaped \" chars, etc.). I put a breakpoint and apparently it doesn't. I suspect that is because the serializer used for that field is not "inherited" as you would expect it. I need to dig in to kotlinx serialization documentation to refresh my memory.

{
val deviceDisplayName = "Device name"
val additionalSpecifications = "value: some additional specifications"
return DefaultDeviceRegistration( deviceDisplayName, additionalSpecifications )
Copy link
Member

Choose a reason for hiding this comment

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

There's a bug here. Or, at least, this doesn't do what the code implies. The second parameter is not additionalSpecifications, but deviceId.

And, deviceId was purposefully added as the last parameter, as in the vast majority of cases you want to not specify that yourself. Maintaining it last would have made this less likely to happen. :)

Furthermore, this method is not really common to both places where it is used. The context is different, and in this case, inlining it and making it more specific to the exact thing being tested makes more sense.

@@ -23,6 +24,16 @@ class DeviceRegistrationTest
assertEquals( default, parsed )
}

@Test
fun can_serialize_and_deserialize_not_null_additional_information()
Copy link
Member

Choose a reason for hiding this comment

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

Unfortunately we don't have support for parameterized tests. At least, back when I set up this project, there was no multiplatform test framework which provided that.

But, this would be more appropriate here. Check out how I reworked this to a poor man's version of the same. :) The downside is it doesn't report individual test results, but I think that is a small price to pay for maintainability/removing code duplication.

Consider it a potentially useful investigation to look at the current status of parameterized tests in kotlin multiplatform.

{
val registration = createDeviceRegistrationWithAdditionalInformation()
var serialized = testJson.encodeToString( DeviceRegistration.serializer(), registration )
serialized = serialized.replace( "dk.cachet.carp.common.application.devices.DefaultDeviceRegistration", "com.unknown.CustomRegistration" )
Copy link
Member

Choose a reason for hiding this comment

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

Not that you could have known, but I've created makeUnknown test helpers before to help setting this up as it become a recurring thing.

@@ -31,7 +31,8 @@
"__type": true,
"deviceId": { "type": "string" },
"deviceDisplayName": { "type": [ "string", "null" ] },
"registrationCreatedOn": { "type": "string", "format": "date-time" }
"registrationCreatedOn": { "type": "string", "format": "date-time" },
"additionalSpecifications": { "type": [ "object", "string", "null" ] }
Copy link
Member

Choose a reason for hiding this comment

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

This can reference ApplicationData.json for consistency with other places where this is used.

@@ -187,6 +187,7 @@ private val bikeBeaconPreregistration = bikeBeacon.createRegistration {
organizationId = UUID( "4e990957-0838-414c-bf25-2d391e2990b5" )
majorId = 42
minorId = 42
additionalSpecifications = "model: 1234"
Copy link
Member

Choose a reason for hiding this comment

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

Similar to applicationData = "{\"uiTheme\": \"black\"}" and other "application data" fields for which examples are created here, let's make this a representative JSON string.

@Whathecode
Copy link
Member

Whathecode commented Sep 30, 2024

Regarding @Required, I found something relevant here in context of a fix I applied.

Missing @Required attributes on fields which should always be serialized but had values assigned by initializers. These fields are needed since the backend does not necessarily have the concrete types available, and these fields are hence not optional. Applying @Required solves that.

That makes sense for fields like DeviceRegistration.deviceId, and definitely PrimaryDeviceConfiguration.isPrimaryDevice, but it seems less relevant for something like additionalSpecifications, which I don't expect to ever have type-specific defaults.

Now I'm actually wondering whether DeviceRegistration.deviceDisplayName even ever needed @Required. It didn't seem like I considered/questioned that in the related PR. I'm thinking not applying @Required (as you did here) is correct, and adding it for deviceDisplayName may have been erroneous due to a naive mimicking of surrounding code.

And, regarding the ApplicationDataSerializer not kicking in, my intuition seems right:

I suspect that is because the serializer used for that field is not "inherited" as you would expect it.

For this to work as expected, you would have to apply @Serializable( ApplicationDataSerializer::class ) to all extending classes of DeviceRegistration. Try applying it to DefaultDeviceRegistration which is used in the test, and see the difference in the serialized output.

@Serializable
@JsExport
data class DefaultDeviceRegistration(
    @Required
    override val deviceDisplayName: String? = null,
    @Serializable( ApplicationDataSerializer::class )
    override val additionalSpecifications: String? = null,
    @Required
    override val deviceId: String = UUID.randomUUID().toString(),
) : DeviceRegistration()

This gives ... "additionalSpecifications":{"OS":"Android 42"} ... as expected, instead of the erroneous ... "additionalSpecifications":"{\"OS\":\"Android 42\"}" ...

That would be a bit unfortunate if there is no way around this. It would be worthwhile checking the kotlinx serialization documentation to see whether they have any (new) features which can avoid the need for doing this.

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.

2 participants