From 0e0d28bf7b950e8857ed7b490f58bcbb4e596e7c Mon Sep 17 00:00:00 2001 From: Yuan Chen <10835085+yuanchen233@users.noreply.github.com> Date: Thu, 26 Sep 2024 20:35:47 +0200 Subject: [PATCH] Add `getActiveParticipationInvitation` test for multiple participants/devices A question arose whether the `getActiveParticipationInvitation()` endpoint returning multiple invitations was a CARP core bug, or a bug in the CARP platform (webservices). This unit test shows this works properly in CARP core. An exception to the detekt rule `DestructuringDeclarationWithTooManyEntries` for test sources was added, as overall it can help clean up otherwise distracting repetitive parts of test setup. Closes #482 --------- Co-authored-by: Steven Jeuris --- .../application/ParticipationServiceTest.kt | 37 ++++++++++++++++ .../infrastructure/test/CreateTestObjects.kt | 43 +++++++++++++++---- detekt.yml | 2 + 3 files changed, 74 insertions(+), 8 deletions(-) diff --git a/carp.deployments.core/src/commonTest/kotlin/dk/cachet/carp/deployments/application/ParticipationServiceTest.kt b/carp.deployments.core/src/commonTest/kotlin/dk/cachet/carp/deployments/application/ParticipationServiceTest.kt index f6efea2a6..1d474c2fb 100644 --- a/carp.deployments.core/src/commonTest/kotlin/dk/cachet/carp/deployments/application/ParticipationServiceTest.kt +++ b/carp.deployments.core/src/commonTest/kotlin/dk/cachet/carp/deployments/application/ParticipationServiceTest.kt @@ -18,6 +18,7 @@ import dk.cachet.carp.deployments.application.users.StudyInvitation import dk.cachet.carp.deployments.domain.createParticipantInvitation import dk.cachet.carp.deployments.domain.users.AccountService import dk.cachet.carp.protocols.infrastructure.test.createSinglePrimaryDeviceProtocol +import dk.cachet.carp.protocols.infrastructure.test.createTwoDevicesAndRolesProtocol import kotlinx.coroutines.test.runTest import kotlin.test.* @@ -77,6 +78,42 @@ interface ParticipationServiceTest assertEquals( setOf( expectedAssignedDevice ), retrievedInvitation.assignedDevices ) } + @Test + fun getActiveParticipationInvitations_returns_invitations_specific_to_account() = runTest { + val (participationService, deploymentService, accountService) = createSUT() + val (protocol, device1, device2, role1, role2) = createTwoDevicesAndRolesProtocol() + val invitation = StudyInvitation( "Test study", "description" ) + val identity1 = AccountIdentity.fromEmailAddress( "role1@test.com" ) + val identity2 = AccountIdentity.fromEmailAddress( "role2@test.com" ) + val participantId1 = UUID.randomUUID() + val participantId2 = UUID.randomUUID() + val participantInvitation1 = + ParticipantInvitation( participantId1, AssignedTo.Roles( setOf( role1 ) ), identity1, invitation ) + val participantInvitation2 = + ParticipantInvitation( participantId2, AssignedTo.Roles( setOf( role2 ) ), identity2, invitation ) + deploymentService.createStudyDeployment( + UUID.randomUUID(), + protocol.getSnapshot(), + listOf( participantInvitation1, participantInvitation2 ) + ) + + val account1 = accountService.findAccount( identity1 ) + assertNotNull( account1 ) + val retrievedInvitation1 = participationService.getActiveParticipationInvitations( account1.id ).singleOrNull() + assertNotNull( retrievedInvitation1 ) + assertEquals( participantId1, retrievedInvitation1.participation.participantId ) + val assignedDevice1 = retrievedInvitation1.assignedDevices.singleOrNull()?.device?.roleName + assertEquals( device1.roleName, assignedDevice1 ) + + val account2 = accountService.findAccount( identity2 ) + assertNotNull( account2 ) + val retrievedInvitation2 = participationService.getActiveParticipationInvitations( account2.id ).singleOrNull() + assertNotNull( retrievedInvitation2 ) + assertEquals( participantId2, retrievedInvitation2.participation.participantId ) + val assignedDevice2 = retrievedInvitation2.assignedDevices.singleOrNull()?.device?.roleName + assertEquals( device2.roleName, assignedDevice2 ) + } + @Test fun getParticipantData_initially_returns_null_for_all_expected_data() = runTest { val (participationService, deploymentService, _) = createSUT() diff --git a/carp.protocols.core/src/commonMain/kotlin/dk/cachet/carp/protocols/infrastructure/test/CreateTestObjects.kt b/carp.protocols.core/src/commonMain/kotlin/dk/cachet/carp/protocols/infrastructure/test/CreateTestObjects.kt index db7589685..0967c3c0d 100644 --- a/carp.protocols.core/src/commonMain/kotlin/dk/cachet/carp/protocols/infrastructure/test/CreateTestObjects.kt +++ b/carp.protocols.core/src/commonMain/kotlin/dk/cachet/carp/protocols/infrastructure/test/CreateTestObjects.kt @@ -5,7 +5,6 @@ import dk.cachet.carp.common.application.data.input.CarpInputDataTypes import dk.cachet.carp.common.application.data.input.InputDataType import dk.cachet.carp.common.application.devices.AnyDeviceConfiguration import dk.cachet.carp.common.application.devices.AnyPrimaryDeviceConfiguration -import dk.cachet.carp.common.application.devices.PrimaryDeviceConfiguration import dk.cachet.carp.common.application.tasks.Measure import dk.cachet.carp.common.application.triggers.TaskControl import dk.cachet.carp.common.application.users.AssignedTo @@ -14,12 +13,7 @@ import dk.cachet.carp.common.application.users.ParticipantAttribute import dk.cachet.carp.common.application.users.ParticipantRole import dk.cachet.carp.common.infrastructure.serialization.JSON import dk.cachet.carp.common.infrastructure.serialization.createDefaultJSON -import dk.cachet.carp.common.infrastructure.test.STUBS_SERIAL_MODULE -import dk.cachet.carp.common.infrastructure.test.STUB_DATA_POINT_TYPE -import dk.cachet.carp.common.infrastructure.test.StubDeviceConfiguration -import dk.cachet.carp.common.infrastructure.test.StubPrimaryDeviceConfiguration -import dk.cachet.carp.common.infrastructure.test.StubTaskConfiguration -import dk.cachet.carp.common.infrastructure.test.StubTriggerConfiguration +import dk.cachet.carp.common.infrastructure.test.* import dk.cachet.carp.protocols.domain.StudyProtocol @@ -64,11 +58,44 @@ fun createSinglePrimaryWithConnectedDeviceProtocol( } data class SinglePrimaryWithConnectedTestProtocol( - val protocoL: StudyProtocol, + val protocol: StudyProtocol, val primary: AnyPrimaryDeviceConfiguration, val connected: AnyDeviceConfiguration ) +/** + * Creates a study protocol with two primary devices, each assigned to a different participant role. + */ +fun createTwoDevicesAndRolesProtocol(): TwoDevicesAndRolesTestProtocol +{ + val protocol = createEmptyProtocol() + val device1 = StubPrimaryDeviceConfiguration( "Device 1" ) + val device2 = StubPrimaryDeviceConfiguration( "Device 2" ) + val role1 = ParticipantRole( "Role 1", isOptional = false ) + val role2 = ParticipantRole( "Role 2", isOptional = false ) + val role1Assignment = AssignedTo.Roles( setOf( role1.role ) ) + val role2Assignment = AssignedTo.Roles( setOf( role2.role ) ) + + with ( protocol ) { + addPrimaryDevice( device1 ) + addPrimaryDevice( device2 ) + addParticipantRole( role1 ) + addParticipantRole( role2 ) + changeDeviceAssignment( device1, role1Assignment ) + changeDeviceAssignment( device2, role2Assignment ) + } + + return TwoDevicesAndRolesTestProtocol( protocol, device1, device2, role1.role, role2.role ) +} + +data class TwoDevicesAndRolesTestProtocol( + val protocol: StudyProtocol, + val device1: AnyPrimaryDeviceConfiguration, + val device2: AnyPrimaryDeviceConfiguration, + val role1Name: String, + val role2Name: String +) + /** * Creates a study protocol with a couple of devices and tasks added. */ diff --git a/detekt.yml b/detekt.yml index fcdb189a4..76c658764 100644 --- a/detekt.yml +++ b/detekt.yml @@ -57,6 +57,8 @@ potential-bugs: style: EqualsNullCall: active: false + DestructuringDeclarationWithTooManyEntries: + excludes: ['**/commonTest/**', '**/jvmTest/**', '**/jsTest/**', '**/test/**'] ForbiddenComment: active: false LoopWithTooManyJumpStatements: