diff --git a/CHANGELOG.md b/CHANGELOG.md index bd93537c..69cf9cd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - report duplication issue in biceps:C11-C15, biceps:C5, biceps:R5046_0, biceps:B-284_0 as well as biceps:R5003. - biceps:5-4-7 tests confusing changes made by SetComponentActivation manipulations with changes made by SetMetricStatus. - glue:R0036_0 test can be blocked by long-running t2iapi RPCs. +- biceps:5025_0 test case could not be satisfied by devices that do not support inserting and removing descriptors. ## [7.0.1] - 2023-03-17 diff --git a/README.md b/README.md index 1243c9eb..65f0e978 100644 --- a/README.md +++ b/README.md @@ -288,7 +288,7 @@ this case in order to minimize the risk of such an invalid application going unn | C-14 | TriggerReport | | C-15 | TriggerReport | | R5024 | TriggerReport | -| R5025_0 | GetRemovableDescriptorsOfClass, RemoveDescriptor, InsertDescriptor | +| R5025_0 | GetRemovableDescriptorsOfClass, RemoveDescriptor, InsertDescriptor, TriggerDescriptorUpdate | | R5046_0 | GetRemovableDescriptorsOfClass, RemoveDescriptor, InsertDescriptor | | R5051 | GetRemovableDescriptorsOfClass, RemoveDescriptor, InsertDescriptor | | R5052 | TriggerAnyDescriptorUpdate | diff --git a/sdccc/pom.xml b/sdccc/pom.xml index 83c1782d..e5d185a0 100644 --- a/sdccc/pom.xml +++ b/sdccc/pom.xml @@ -172,7 +172,7 @@ com.draeger.medical t2iapi - 3.0.0.262 + 3.0.0.296 diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/FallbackManipulations.java b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/FallbackManipulations.java index b2d178ba..64d8af26 100644 --- a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/FallbackManipulations.java +++ b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/FallbackManipulations.java @@ -234,6 +234,19 @@ public void close() {} return interactionResult ? ResponseTypes.Result.RESULT_SUCCESS : ResponseTypes.Result.RESULT_FAIL; } + @Override + public ResponseTypes.Result triggerDescriptorUpdate(final List handles) { + final var triggerReportString = "Trigger a descriptor update for handles %s"; + final var interactionMessage = String.format(triggerReportString, String.join(", ", handles)); + final var interactionResult = interactionFactory + .createUserInteraction(new FilterInputStream(System.in) { + @Override + public void close() {} + }) + .displayYesNoUserInteraction(interactionMessage); + return interactionResult ? ResponseTypes.Result.RESULT_SUCCESS : ResponseTypes.Result.RESULT_FAIL; + } + @Override public ResponseTypes.Result triggerAnyDescriptorUpdate() { final var interactionMessage = "Trigger a descriptor update for some descriptor"; diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/GRpcManipulations.java b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/GRpcManipulations.java index 57283c20..05ce40e9 100644 --- a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/GRpcManipulations.java +++ b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/GRpcManipulations.java @@ -294,15 +294,21 @@ public ResponseTypes.Result setMetricStatus( @Override public ResponseTypes.Result triggerDescriptorUpdate(final String handle) { - final var message = - BasicRequests.BasicHandleRequest.newBuilder().setHandle(handle).build(); + return triggerDescriptorUpdate(List.of(handle)); + } + + @Override + public ResponseTypes.Result triggerDescriptorUpdate(final List handles) { + final var message = DeviceRequests.TriggerDescriptorUpdateRequest.newBuilder() + .addAllHandle(handles) + .build(); return performCallWrapper( v -> deviceStub.triggerDescriptorUpdate(message), - v -> fallback.triggerDescriptorUpdate(handle), + v -> fallback.triggerDescriptorUpdate(handles), BasicResponses.BasicResponse::getResult, BasicResponses.BasicResponse::getResult, - ManipulationParameterUtil.buildHandleManipulationParameterData(handle)); + ManipulationParameterUtil.buildTriggerDescriptorUpdateParameterData(handles)); } @Override diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/Manipulations.java b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/Manipulations.java index 64fbd73a..639f7e8d 100644 --- a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/Manipulations.java +++ b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/Manipulations.java @@ -137,6 +137,14 @@ ResponseTypes.Result setMetricStatus( */ ResponseTypes.Result triggerDescriptorUpdate(String handle); + /** + * Trigger a descriptor update for the provided descriptor handles. + * + * @param handles list of descriptor handles to trigger an update for. + * @return the result of the manipulation + */ + ResponseTypes.Result triggerDescriptorUpdate(List handles); + /** * Trigger a descriptor update for some descriptor (chosen by the device). * diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ConditionalPreconditions.java b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ConditionalPreconditions.java index e93e8762..2494891c 100644 --- a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ConditionalPreconditions.java +++ b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ConditionalPreconditions.java @@ -461,11 +461,11 @@ static boolean manipulation(final Injector injector) { } // all options exhausted and the goal is still not reached - LOG.error("Unable to find any MdsDescriptors using the GetRemovableDescriptorsOfType() manipulation " + LOG.error("Unable to find any MdsDescriptors using the GetRemovableDescriptorsOfClass() manipulation " + "that can be inserted, updated and removed (at least one for each is required for the test " + "applying this precondition). " + "Please check if the test case applying this precondition is applicable to your device and if the " - + "GetRemovableDescriptorsOfType, InsertDescriptor, RemoveDescriptor, and TriggerDescriptorUpdate " + + "GetRemovableDescriptorsOfClass, InsertDescriptor, RemoveDescriptor, and TriggerDescriptorUpdate " + "manipulations have been implemented correctly."); return false; } @@ -660,15 +660,17 @@ static boolean manipulation(final Injector injector) { * Precondition which checks whether DescriptionModificationReport messages containing an insertion * or deletion have been received, triggering description changes otherwise. */ - public static class DescriptionChangedPrecondition extends SimplePrecondition { + public static class DescriptionModificationCrtOrDelPrecondition extends SimplePrecondition { - private static final Logger LOG = LogManager.getLogger(DescriptionChangedPrecondition.class); + private static final Logger LOG = LogManager.getLogger(DescriptionModificationCrtOrDelPrecondition.class); /** - * Creates a description changed precondition check. + * Creates a description modification crt or del precondition check. */ - public DescriptionChangedPrecondition() { - super(DescriptionChangedPrecondition::preconditionCheck, DescriptionChangedPrecondition::manipulation); + public DescriptionModificationCrtOrDelPrecondition() { + super( + DescriptionModificationCrtOrDelPrecondition::preconditionCheck, + DescriptionModificationCrtOrDelPrecondition::manipulation); } static boolean preconditionCheck(final Injector injector) throws PreconditionException { diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ManipulationPreconditions.java b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ManipulationPreconditions.java index db31af2e..f3199a0e 100644 --- a/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ManipulationPreconditions.java +++ b/sdccc/src/main/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ManipulationPreconditions.java @@ -10,6 +10,7 @@ import com.draeger.medical.sdccc.configuration.TestSuiteConfig; import com.draeger.medical.sdccc.manipulation.Manipulations; import com.draeger.medical.sdccc.manipulation.precondition.ManipulationPrecondition; +import com.draeger.medical.sdccc.manipulation.precondition.PreconditionException; import com.draeger.medical.sdccc.sdcri.testclient.TestClient; import com.draeger.medical.sdccc.tests.util.ImpliedValueUtil; import com.draeger.medical.sdccc.util.TestRunObserver; @@ -29,6 +30,7 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; +import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.somda.sdc.biceps.common.MdibEntity; @@ -38,6 +40,7 @@ import org.somda.sdc.biceps.common.event.ContextStateModificationMessage; import org.somda.sdc.biceps.model.participant.AbstractAlertState; import org.somda.sdc.biceps.model.participant.AbstractContextState; +import org.somda.sdc.biceps.model.participant.AbstractDescriptor; import org.somda.sdc.biceps.model.participant.AbstractDeviceComponentDescriptor; import org.somda.sdc.biceps.model.participant.AbstractDeviceComponentState; import org.somda.sdc.biceps.model.participant.AbstractMetricDescriptor; @@ -55,6 +58,7 @@ import org.somda.sdc.biceps.model.participant.ContextAssociation; import org.somda.sdc.biceps.model.participant.LocationContextDescriptor; import org.somda.sdc.biceps.model.participant.LocationContextState; +import org.somda.sdc.biceps.model.participant.MdsDescriptor; import org.somda.sdc.biceps.model.participant.MetricCategory; import org.somda.sdc.biceps.model.participant.PatientContextDescriptor; import org.somda.sdc.biceps.model.participant.PatientContextState; @@ -114,6 +118,114 @@ private static boolean manipulateMetricStatus( return manipulationResults.contains(ResponseTypes.Result.RESULT_SUCCESS); } + private static boolean removeAndReinsertDescriptors(final Injector injector, final Logger log) { + final var manipulations = injector.getInstance(Manipulations.class); + final var testClient = injector.getInstance(TestClient.class); + final var testRunObserver = injector.getInstance(TestRunObserver.class); + + final MdibAccess mdibAccess; + final SdcRemoteDevice remoteDevice; + + remoteDevice = testClient.getSdcRemoteDevice(); + if (remoteDevice == null) { + testRunObserver.invalidateTestRun("Remote device could not be accessed, likely due to a disconnect"); + return false; + } + + mdibAccess = remoteDevice.getMdibAccess(); + + final var modifiableDescriptors = manipulations.getRemovableDescriptorsOfClass(); + if (modifiableDescriptors.isEmpty()) { + log.info("No modifiable descriptors available for manipulation"); + return false; + } + + final var manipulationResults = new HashSet(); + for (String handle : modifiableDescriptors) { + // determine if descriptor is currently present + var descriptorEntity = mdibAccess.getEntity(handle); + log.debug("Descriptor {} presence: {}", handle, descriptorEntity.isPresent()); + + // if the descriptor is not present, insert it first + if (descriptorEntity.isEmpty()) { + manipulationResults.add(manipulations.insertDescriptor(handle)); + descriptorEntity = mdibAccess.getEntity(handle); + if (descriptorEntity.isEmpty()) { + manipulationResults.add(ResponseTypes.Result.RESULT_FAIL); + } + log.debug("Descriptor {} presence: {}", handle, descriptorEntity.isPresent()); + } + + // remove descriptor + manipulationResults.add(manipulations.removeDescriptor(handle)); + descriptorEntity = mdibAccess.getEntity(handle); + if (descriptorEntity.isPresent()) { + manipulationResults.add(ResponseTypes.Result.RESULT_FAIL); + } + log.debug("Descriptor {} presence: {}", handle, descriptorEntity.isPresent()); + + // reinsert descriptor + manipulationResults.add(manipulations.insertDescriptor(handle)); + descriptorEntity = mdibAccess.getEntity(handle); + if (descriptorEntity.isEmpty()) { + manipulationResults.add(ResponseTypes.Result.RESULT_FAIL); + } + log.debug("Descriptor {} presence: {}", handle, descriptorEntity.isPresent()); + + if (manipulationResults.contains(ResponseTypes.Result.RESULT_FAIL)) { + testRunObserver.invalidateTestRun(String.format( + "Could not successfully modify descriptor %s, stopping the precondition", handle)); + break; + } + } + + return !manipulationResults.contains(ResponseTypes.Result.RESULT_FAIL) + && !manipulationResults.contains(ResponseTypes.Result.RESULT_NOT_IMPLEMENTED) + && manipulationResults.contains(ResponseTypes.Result.RESULT_SUCCESS); + } + + private static boolean descriptionUpdateWithParentChildRelationshipManipulation( + final Injector injector, final Logger log) { + final Pair descriptorHandles = findFirstDescriptorHandleWithChildren(injector, log); + if (descriptorHandles == null) { + log.error("Could not trigger a descriptor update with parent child relationship as there are no " + + "descriptors with children in the mdib."); + return false; + } + final String parentDescriptorHandle = descriptorHandles.getLeft(); + final String childDescriptorHandle = descriptorHandles.getRight(); + final var manipulations = injector.getInstance(Manipulations.class); + + final ResponseTypes.Result manipulationResult = + manipulations.triggerDescriptorUpdate(List.of(childDescriptorHandle, parentDescriptorHandle)); + + return ResponseTypes.Result.RESULT_SUCCESS.equals(manipulationResult); + } + + private static Pair findFirstDescriptorHandleWithChildren( + final Injector injector, final Logger log) { + final var testClient = injector.getInstance(TestClient.class); + + final var remoteDevice = testClient.getSdcRemoteDevice(); + if (remoteDevice == null) { + log.error("remote device could not be accessed, likely due to a disconnect"); + return null; + } + final var mdibAccess = remoteDevice.getMdibAccess(); + + final Collection entities = mdibAccess.findEntitiesByType(AbstractDescriptor.class); + for (MdibEntity entity : entities) { + if (entity.getDescriptor() instanceof MdsDescriptor) { + continue; // we are not interested in MdsDescriptors as many Devices do not support modifying them. + } + final List children = entity.getChildren(); + if (!children.isEmpty()) { + return Pair.of(entity.getHandle(), children.get(0)); + } + } + return null; + } + /** * Associates two new patients for every available PatientContextDescriptor present in the provider mdib. */ @@ -1607,69 +1719,37 @@ public RemoveAndReinsertDescriptorManipulation() { * @return true if successful, false otherwise */ static boolean manipulation(final Injector injector) { - final var manipulations = injector.getInstance(Manipulations.class); - final var testClient = injector.getInstance(TestClient.class); - final var testRunObserver = injector.getInstance(TestRunObserver.class); - - final MdibAccess mdibAccess; - final SdcRemoteDevice remoteDevice; - - remoteDevice = testClient.getSdcRemoteDevice(); - if (remoteDevice == null) { - testRunObserver.invalidateTestRun("Remote device could not be accessed, likely due to a disconnect"); - return false; - } - - mdibAccess = remoteDevice.getMdibAccess(); - - final var modifiableDescriptors = manipulations.getRemovableDescriptorsOfClass(); - if (modifiableDescriptors.isEmpty()) { - LOG.info("No modifiable descriptors available for manipulation"); - return false; - } - - final var manipulationResults = new HashSet(); - for (String handle : modifiableDescriptors) { - // determine if descriptor is currently present - var descriptorEntity = mdibAccess.getEntity(handle); - LOG.debug("Descriptor {} presence: {}", handle, descriptorEntity.isPresent()); - - // if the descriptor is not present, insert it first - if (descriptorEntity.isEmpty()) { - manipulationResults.add(manipulations.insertDescriptor(handle)); - descriptorEntity = mdibAccess.getEntity(handle); - if (descriptorEntity.isEmpty()) { - manipulationResults.add(ResponseTypes.Result.RESULT_FAIL); - } - LOG.debug("Descriptor {} presence: {}", handle, descriptorEntity.isPresent()); - } + return removeAndReinsertDescriptors(injector, LOG); + } + } - // remove descriptor - manipulationResults.add(manipulations.removeDescriptor(handle)); - descriptorEntity = mdibAccess.getEntity(handle); - if (descriptorEntity.isPresent()) { - manipulationResults.add(ResponseTypes.Result.RESULT_FAIL); - } - LOG.debug("Descriptor {} presence: {}", handle, descriptorEntity.isPresent()); + /** + * Precondition which triggers all possible description changes with parent-child relationships. + */ + public static class DescriptionModificationAllWithParentChildRelationshipPrecondition + extends ManipulationPrecondition { - // reinsert descriptor - manipulationResults.add(manipulations.insertDescriptor(handle)); - descriptorEntity = mdibAccess.getEntity(handle); - if (descriptorEntity.isEmpty()) { - manipulationResults.add(ResponseTypes.Result.RESULT_FAIL); - } - LOG.debug("Descriptor {} presence: {}", handle, descriptorEntity.isPresent()); + private static final Logger LOG = + LogManager.getLogger(DescriptionModificationAllWithParentChildRelationshipPrecondition.class); - if (manipulationResults.contains(ResponseTypes.Result.RESULT_FAIL)) { - testRunObserver.invalidateTestRun(String.format( - "Could not successfully modify descriptor %s, stopping the precondition", handle)); - break; - } - } + /** + * Creates a description modification all with parent child relationship precondition check. + */ + public DescriptionModificationAllWithParentChildRelationshipPrecondition() { + super(DescriptionModificationAllWithParentChildRelationshipPrecondition::manipulation); + } - return !manipulationResults.contains(ResponseTypes.Result.RESULT_FAIL) - && !manipulationResults.contains(ResponseTypes.Result.RESULT_NOT_IMPLEMENTED) - && manipulationResults.contains(ResponseTypes.Result.RESULT_SUCCESS); + /** + * Performs the removal, reinsertion and update of all modifiable descriptors in the mdib to trigger reports. + * + * @param injector to analyze mdib on + * @return true if successful, false otherwise + * @throws PreconditionException on errors + */ + static boolean manipulation(final Injector injector) { + final boolean result1 = removeAndReinsertDescriptors(injector, LOG); + final boolean result2 = descriptionUpdateWithParentChildRelationshipManipulation(injector, LOG); + return result1 || result2; } } } diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/tests/biceps/invariant/InvariantMessageModelAnnexTest.java b/sdccc/src/main/java/com/draeger/medical/sdccc/tests/biceps/invariant/InvariantMessageModelAnnexTest.java index 6416d3b1..f0a1edb2 100644 --- a/sdccc/src/main/java/com/draeger/medical/sdccc/tests/biceps/invariant/InvariantMessageModelAnnexTest.java +++ b/sdccc/src/main/java/com/draeger/medical/sdccc/tests/biceps/invariant/InvariantMessageModelAnnexTest.java @@ -15,6 +15,7 @@ import com.draeger.medical.sdccc.configuration.EnabledTestConfig; import com.draeger.medical.sdccc.manipulation.precondition.impl.ConditionalPreconditions; +import com.draeger.medical.sdccc.manipulation.precondition.impl.ManipulationPreconditions; import com.draeger.medical.sdccc.messages.MessageStorage; import com.draeger.medical.sdccc.messages.mapping.MessageContent; import com.draeger.medical.sdccc.sdcri.testclient.TestClient; @@ -332,7 +333,9 @@ void testRequirementR5024() throws NoTestData, IOException { @TestDescription("For every DescriptionModificationReport received from the DUT, and for all parent-child" + " relationships between the elements contained in the report, checks that the reportPart containing" + " the parent comes before the reportPart containing the child.") - @RequirePrecondition(simplePreconditions = ConditionalPreconditions.DescriptionChangedPrecondition.class) + @RequirePrecondition( + manipulationPreconditions = + ManipulationPreconditions.DescriptionModificationAllWithParentChildRelationshipPrecondition.class) void testRequirementR5025() throws NoTestData, IOException { try (final var messages = messageStorage.getInboundMessagesByBodyType(Constants.MSG_DESCRIPTION_MODIFICATION_REPORT)) { @@ -353,7 +356,10 @@ void testRequirementR5025() throws NoTestData, IOException { assertTestData( descriptorsSeen.get(), "No DescriptionModificationReports with Parent-Child Relationships between Descriptors " - + " seen during test run, test failed."); + + " seen during test run, test failed." + + " Please make sure that the device either supports descriptor updates or that the list" + + " of removable descriptors returned by the getRemovableDescriptors() manipulation" + + " includes at least one descriptor that has child descriptors."); } } diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/tests/biceps/invariant/InvariantParticipantModelVersioningTest.java b/sdccc/src/main/java/com/draeger/medical/sdccc/tests/biceps/invariant/InvariantParticipantModelVersioningTest.java index a07d948b..0e8d37c5 100644 --- a/sdccc/src/main/java/com/draeger/medical/sdccc/tests/biceps/invariant/InvariantParticipantModelVersioningTest.java +++ b/sdccc/src/main/java/com/draeger/medical/sdccc/tests/biceps/invariant/InvariantParticipantModelVersioningTest.java @@ -80,7 +80,8 @@ void setUp() { @TestDescription( "Starting from the initially retrieved mdib, applies every episodic report to the mdib and" + " verifies that descriptor versions are incremented by 1 whenever a child descriptor is added or deleted.") - @RequirePrecondition(simplePreconditions = {ConditionalPreconditions.DescriptionChangedPrecondition.class}) + @RequirePrecondition( + simplePreconditions = {ConditionalPreconditions.DescriptionModificationCrtOrDelPrecondition.class}) void testRequirementR0033() throws NoTestData, IOException { final var mdibHistorian = mdibHistorianFactory.createMdibHistorian( messageStorage, getInjector().getInstance(TestRunObserver.class)); diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/tests/util/ManipulationParameterUtil.java b/sdccc/src/main/java/com/draeger/medical/sdccc/tests/util/ManipulationParameterUtil.java index 1f653ba4..1fd762a8 100644 --- a/sdccc/src/main/java/com/draeger/medical/sdccc/tests/util/ManipulationParameterUtil.java +++ b/sdccc/src/main/java/com/draeger/medical/sdccc/tests/util/ManipulationParameterUtil.java @@ -48,6 +48,17 @@ public static ManipulationParameterData buildHandleManipulationParameterData(fin List.of(new ImmutablePair<>(Constants.MANIPULATION_PARAMETER_HANDLE, handle))); } + /** + * Build manipulation parameter data containing the handles that are needed for the manipulation. + * + * @param handles for which manipulation parameter data will be built. + * @return the manipulation parameter data + */ + public static ManipulationParameterData buildTriggerDescriptorUpdateParameterData(final List handles) { + return new ManipulationParameterData( + List.of(new ImmutablePair<>(Constants.MANIPULATION_PARAMETER_HANDLES, String.join(", ", handles)))); + } + /** * Build manipulation parameter data containing the location detail that is needed for the manipulation. * diff --git a/sdccc/src/main/java/com/draeger/medical/sdccc/util/Constants.java b/sdccc/src/main/java/com/draeger/medical/sdccc/util/Constants.java index c9308c7c..a29b84ac 100644 --- a/sdccc/src/main/java/com/draeger/medical/sdccc/util/Constants.java +++ b/sdccc/src/main/java/com/draeger/medical/sdccc/util/Constants.java @@ -222,6 +222,7 @@ public final class Constants { // Manipulation Data for Hibernation public static final String MANIPULATION_PARAMETER_HANDLE = "Handle"; + public static final String MANIPULATION_PARAMETER_HANDLES = "Handles"; public static final String MANIPULATION_PARAMETER_SEQUENCE_ID = "SequenceId"; public static final String MANIPULATION_PARAMETER_LOCATION_DETAIL = "LocationDetail"; public static final String MANIPULATION_PARAMETER_CONTEXT_ASSOCIATION = "ContextAssociation"; diff --git a/sdccc/src/test/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ConditionalPreconditionsTest.java b/sdccc/src/test/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ConditionalPreconditionsTest.java index 23662726..6cbab165 100644 --- a/sdccc/src/test/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ConditionalPreconditionsTest.java +++ b/sdccc/src/test/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ConditionalPreconditionsTest.java @@ -282,10 +282,11 @@ protected void configure() { */ @Test @DisplayName("DescriptionChangedPrecondition correctly checks for precondition") - public void testDescriptionModificationPreconditionCheck() + public void testDescriptionModificationCrtOrDelPreconditionCheck() throws PreconditionException, IOException, JAXBException { // no messages - assertFalse(ConditionalPreconditions.DescriptionChangedPrecondition.preconditionCheck(testInjector)); + assertFalse( + ConditionalPreconditions.DescriptionModificationCrtOrDelPrecondition.preconditionCheck(testInjector)); final var reportPart = messageBuilder.buildDescriptionModificationReportReportPart(); reportPart.setModificationType(DescriptionModificationType.CRT); @@ -297,7 +298,8 @@ public void testDescriptionModificationPreconditionCheck() messageStorageUtil.addInboundSecureHttpMessage(storage, message); - assertTrue(ConditionalPreconditions.DescriptionChangedPrecondition.preconditionCheck(testInjector)); + assertTrue( + ConditionalPreconditions.DescriptionModificationCrtOrDelPrecondition.preconditionCheck(testInjector)); } /** @@ -334,7 +336,7 @@ public void testDescriptionModificationManipulation() { } }); - assertTrue(ConditionalPreconditions.DescriptionChangedPrecondition.manipulation(testInjector)); + assertTrue(ConditionalPreconditions.DescriptionModificationCrtOrDelPrecondition.manipulation(testInjector)); final var insertCaptor = ArgumentCaptor.forClass(String.class); final var removeCaptor = ArgumentCaptor.forClass(String.class); @@ -640,7 +642,7 @@ public void testDescriptionModificationDelManipulation() { @DisplayName("DescriptionModificationPrecondition throws exception if no removable descriptors are present") void testDescriptionModificationModificationNoDescriptors() { // must fail without any removable descriptors - assertFalse(ConditionalPreconditions.DescriptionChangedPrecondition.manipulation(testInjector)); + assertFalse(ConditionalPreconditions.DescriptionModificationCrtOrDelPrecondition.manipulation(testInjector)); reset(mockManipulations); } diff --git a/sdccc/src/test/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ManipulationPreconditionsTest.java b/sdccc/src/test/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ManipulationPreconditionsTest.java index 199b5142..1da74afb 100644 --- a/sdccc/src/test/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ManipulationPreconditionsTest.java +++ b/sdccc/src/test/java/com/draeger/medical/sdccc/manipulation/precondition/impl/ManipulationPreconditionsTest.java @@ -13,6 +13,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; @@ -24,6 +25,8 @@ import com.draeger.medical.sdccc.manipulation.Manipulations; import com.draeger.medical.sdccc.sdcri.testclient.TestClient; +import com.draeger.medical.sdccc.sdcri.testclient.TestClientUtil; +import com.draeger.medical.sdccc.tests.InjectorTestBase; import com.draeger.medical.sdccc.tests.test_util.InjectorUtil; import com.draeger.medical.sdccc.util.MdibBuilder; import com.draeger.medical.sdccc.util.TestRunObserver; @@ -32,6 +35,7 @@ import com.google.inject.Injector; import java.io.IOException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -47,6 +51,7 @@ import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; +import org.mockito.stubbing.Answer; import org.somda.sdc.biceps.common.MdibEntity; import org.somda.sdc.biceps.common.access.MdibAccess; import org.somda.sdc.biceps.common.access.MdibAccessObservable; @@ -95,7 +100,6 @@ public class ManipulationPreconditionsTest { private static final String ALERT_SYSTEM_CONTEXT_HANDLE2 = "alerthandle2"; private static final String ALERT_CONDITION_HANDLE = "alertconditionhandle"; private static final String ALERT_CONDITION_HANDLE2 = "alertconditionhandle2"; - private static final String ALERT_SIGNAL_HANDLE = "alertSignalHandle"; private static final String AUD_ALERT_SIGNAL_HANDLE = "audAlertSignalHandle"; private static final String OTH_ALERT_SIGNAL_HANDLE = "othAlertSignalHandle"; private static final String TAN_ALERT_SIGNAL_HANDLE = "tanAlertSignalHandle"; @@ -188,7 +192,11 @@ void setUp() throws IOException { mockMdibAccess = mock(MdibAccess.class, Answers.RETURNS_DEEP_STUBS); mockTestClient = mock(TestClient.class, Answers.RETURNS_DEEP_STUBS); + final var clientInjector = TestClientUtil.createClientInjector(); when(mockTestClient.getSdcRemoteDevice()).thenReturn(mockDevice); + when(mockTestClient.isClientRunning()).thenReturn(true); + when(mockTestClient.getSdcRemoteDevice()).thenReturn(mockDevice); + when(mockTestClient.getInjector()).thenReturn(clientInjector); injector = InjectorUtil.setupInjector(new AbstractModule() { @Override @@ -199,6 +207,7 @@ protected void configure() { } }); + InjectorTestBase.setInjector(injector); testRunObserver = injector.getInstance(TestRunObserver.class); } @@ -1897,4 +1906,279 @@ void testSystemSignalActivationSomeFail() { assertFalse(ManipulationPreconditions.SystemSignalActivationManipulation.manipulation(injector)); } + + @Test + @DisplayName("DescriptionModificationAllWithParentChildRelationshipPrecondition correctly calls manipulation") + void testDescriptionModificationAllWithParentChildRelationshipPreconditionManipulation() { + + final var descriptor1Handle = "superHandle"; + final var descriptor2Handle = "handle;Süper;"; + final var parentDescriptorHandle = "parentHandle"; + final var childDescriptorHandle = "childHandle"; + + final var presenceMap = new HashMap<>(Map.of( + descriptor1Handle, false, + descriptor2Handle, true)); + + when(mockManipulations.getRemovableDescriptorsOfClass()) + .thenReturn(List.of(descriptor1Handle, descriptor2Handle)); + + when(mockManipulations.insertDescriptor(anyString())).thenAnswer((Answer) invocation -> { + presenceMap.put(invocation.getArgument(0), true); + return ResponseTypes.Result.RESULT_SUCCESS; + }); + when(mockManipulations.removeDescriptor(anyString())).thenAnswer((Answer) invocation -> { + presenceMap.put(invocation.getArgument(0), false); + return ResponseTypes.Result.RESULT_SUCCESS; + }); + when(mockManipulations.triggerDescriptorUpdate(anyList())).thenReturn(ResponseTypes.Result.RESULT_SUCCESS); + final MdibEntity mockEntityB2 = mock(MdibEntity.class); + when(mockEntityB2.getHandle()).thenReturn(parentDescriptorHandle); + when(mockEntityB2.getChildren()).thenReturn(List.of(childDescriptorHandle)); + when(mockTestClient.getSdcRemoteDevice().getMdibAccess().findEntitiesByType(any())) + .thenReturn(List.of(mockEntityB2)); + final MdibEntity mockEntityB3 = mock(MdibEntity.class); + when(mockTestClient.getSdcRemoteDevice().getMdibAccess().getEntity(any())) + .thenAnswer(args -> { + if (presenceMap.get((String) args.getArgument(0))) { + return Optional.of(mockEntityB3); + } else { + return Optional.empty(); + } + }); + + assertTrue( + ManipulationPreconditions.DescriptionModificationAllWithParentChildRelationshipPrecondition + .manipulation(injector)); + + final var insertCaptor = ArgumentCaptor.forClass(String.class); + final var removeCaptor = ArgumentCaptor.forClass(String.class); + final var handleCaptor = ArgumentCaptor.forClass(List.class); + verify(mockManipulations, times(1)).getRemovableDescriptorsOfClass(); + verify(mockManipulations, times(3)).insertDescriptor(insertCaptor.capture()); + verify(mockManipulations, times(2)).removeDescriptor(removeCaptor.capture()); + verify(mockManipulations, times(1)).triggerDescriptorUpdate(handleCaptor.capture()); + + assertEquals(2, handleCaptor.getAllValues().get(0).size()); + assertEquals(childDescriptorHandle, handleCaptor.getAllValues().get(0).get(0)); + assertEquals(parentDescriptorHandle, handleCaptor.getAllValues().get(0).get(1)); + + assertEquals( + 2, + insertCaptor.getAllValues().stream() + .filter(descriptor1Handle::equals) + .count()); + assertEquals( + 1, + insertCaptor.getAllValues().stream() + .filter(descriptor2Handle::equals) + .count()); + + assertEquals( + 1, + removeCaptor.getAllValues().stream() + .filter(descriptor1Handle::equals) + .count()); + assertEquals( + 1, + removeCaptor.getAllValues().stream() + .filter(descriptor2Handle::equals) + .count()); + } + + @Test + @DisplayName( + "DescriptionModificationAllWithParentChildRelationshipPrecondition when GetRemovableDescriptors failed.") + void + testDescriptionModificationAllWithParentChildRelationshipPreconditionManipulationGetRemovableDescriptorsFailed() { + + final var descriptor1Handle = "superHandle"; + final var descriptor2Handle = "handle;Süper;"; + final var parentDescriptorHandle = "parentHandle"; + final var childDescriptorHandle = "childHandle"; + + final var presenceMap = new HashMap<>(Map.of( + descriptor1Handle, false, + descriptor2Handle, true)); + + when(mockManipulations.getRemovableDescriptorsOfClass()) + .thenReturn(List.of()); // When the manipulation is NOT_SUPPORTED, an empty list is returned. + + when(mockManipulations.insertDescriptor(anyString())).thenAnswer((Answer) invocation -> { + presenceMap.put(invocation.getArgument(0), true); + return ResponseTypes.Result.RESULT_SUCCESS; + }); + when(mockManipulations.removeDescriptor(anyString())).thenAnswer((Answer) invocation -> { + presenceMap.put(invocation.getArgument(0), false); + return ResponseTypes.Result.RESULT_SUCCESS; + }); + when(mockManipulations.triggerDescriptorUpdate(anyList())).thenReturn(ResponseTypes.Result.RESULT_SUCCESS); + final MdibEntity mockEntityB = mock(MdibEntity.class); + when(mockEntityB.getHandle()).thenReturn(parentDescriptorHandle); + when(mockEntityB.getChildren()).thenReturn(List.of(childDescriptorHandle)); + when(mockTestClient.getSdcRemoteDevice().getMdibAccess().findEntitiesByType(any())) + .thenReturn(List.of(mockEntityB)); + final MdibEntity mockEntityB2 = mock(MdibEntity.class); + when(mockTestClient.getSdcRemoteDevice().getMdibAccess().getEntity(any())) + .thenAnswer(args -> { + if (presenceMap.get((String) args.getArgument(0))) { + return Optional.of(mockEntityB2); + } else { + return Optional.empty(); + } + }); + + assertTrue( + ManipulationPreconditions.DescriptionModificationAllWithParentChildRelationshipPrecondition + .manipulation(injector)); + + final var handleCaptor = ArgumentCaptor.forClass(List.class); + verify(mockManipulations, times(1)).getRemovableDescriptorsOfClass(); + verify(mockManipulations, times(0)).insertDescriptor(any()); + verify(mockManipulations, times(0)).removeDescriptor(any()); + verify(mockManipulations, times(1)).triggerDescriptorUpdate(handleCaptor.capture()); + + assertEquals(2, handleCaptor.getAllValues().get(0).size()); + assertEquals(childDescriptorHandle, handleCaptor.getAllValues().get(0).get(0)); + assertEquals(parentDescriptorHandle, handleCaptor.getAllValues().get(0).get(1)); + } + + @Test + @DisplayName( + "DescriptionModificationAllWithParentChildRelationshipPrecondition when TriggerDescriptorUpdate failed") + void testDescriptionModificationAllWithParentChildRelationshipPreconditionManipulationFailed2() { + + final var descriptor1Handle = "superHandle"; + final var descriptor2Handle = "handle;Süper;"; + final var parentDescriptorHandle = "parentHandle"; + final var childDescriptorHandle = "childHandle"; + + final var presenceMap = new HashMap<>(Map.of( + descriptor1Handle, false, + descriptor2Handle, true)); + + when(mockManipulations.getRemovableDescriptorsOfClass()) + .thenReturn(List.of(descriptor1Handle, descriptor2Handle)); + + when(mockManipulations.insertDescriptor(anyString())).thenAnswer((Answer) invocation -> { + presenceMap.put(invocation.getArgument(0), true); + return ResponseTypes.Result.RESULT_SUCCESS; + }); + when(mockManipulations.removeDescriptor(anyString())).thenAnswer((Answer) invocation -> { + presenceMap.put(invocation.getArgument(0), false); + return ResponseTypes.Result.RESULT_SUCCESS; + }); + when(mockManipulations.triggerDescriptorUpdate(anyList())).thenReturn(ResponseTypes.Result.RESULT_FAIL); + final MdibEntity mockEntityB = mock(MdibEntity.class); + when(mockEntityB.getHandle()).thenReturn(parentDescriptorHandle); + when(mockEntityB.getChildren()).thenReturn(List.of(childDescriptorHandle)); + when(mockTestClient.getSdcRemoteDevice().getMdibAccess().findEntitiesByType(any())) + .thenReturn(List.of(mockEntityB)); + final MdibEntity mockEntityB2 = mock(MdibEntity.class); + when(mockTestClient.getSdcRemoteDevice().getMdibAccess().getEntity(any())) + .thenAnswer(args -> { + if (presenceMap.get((String) args.getArgument(0))) { + return Optional.of(mockEntityB2); + } else { + return Optional.empty(); + } + }); + + assertTrue( + ManipulationPreconditions.DescriptionModificationAllWithParentChildRelationshipPrecondition + .manipulation(injector)); + + final var insertCaptor = ArgumentCaptor.forClass(String.class); + final var removeCaptor = ArgumentCaptor.forClass(String.class); + final var handleCaptor = ArgumentCaptor.forClass(List.class); + verify(mockManipulations, times(1)).getRemovableDescriptorsOfClass(); + verify(mockManipulations, times(3)).insertDescriptor(insertCaptor.capture()); + verify(mockManipulations, times(2)).removeDescriptor(removeCaptor.capture()); + verify(mockManipulations, times(1)).triggerDescriptorUpdate(handleCaptor.capture()); + + assertEquals(2, handleCaptor.getAllValues().get(0).size()); + assertEquals(childDescriptorHandle, handleCaptor.getAllValues().get(0).get(0)); + assertEquals(parentDescriptorHandle, handleCaptor.getAllValues().get(0).get(1)); + + assertEquals( + 2, + insertCaptor.getAllValues().stream() + .filter(descriptor1Handle::equals) + .count()); + assertEquals( + 1, + insertCaptor.getAllValues().stream() + .filter(descriptor2Handle::equals) + .count()); + + assertEquals( + 1, + removeCaptor.getAllValues().stream() + .filter(descriptor1Handle::equals) + .count()); + assertEquals( + 1, + removeCaptor.getAllValues().stream() + .filter(descriptor2Handle::equals) + .count()); + } + + @Test + @DisplayName("DescriptionModificationAllWithParentChildRelationshipPrecondition when both GetRemovableDescriptors " + + "and TriggerDescriptorUpdate fail") + void testDescriptionModificationAllWithParentChildRelationshipPreconditionManipulationFailed3() { + + final var descriptor1Handle = "superHandle"; + final var descriptor2Handle = "handle;Süper;"; + final var parentDescriptorHandle = "parentHandle"; + final var childDescriptorHandle = "childHandle"; + + final var presenceMap = new HashMap<>(Map.of( + descriptor1Handle, false, + descriptor2Handle, true)); + + when(mockManipulations.getRemovableDescriptorsOfClass()) + .thenReturn(List.of()); // When the manipulation returns RESULT_NOT_SUPPORTED, then an empty list + // is returned + + when(mockManipulations.insertDescriptor(anyString())).thenAnswer((Answer) invocation -> { + presenceMap.put(invocation.getArgument(0), true); + return ResponseTypes.Result.RESULT_SUCCESS; + }); + when(mockManipulations.removeDescriptor(anyString())).thenAnswer((Answer) invocation -> { + presenceMap.put(invocation.getArgument(0), false); + return ResponseTypes.Result.RESULT_SUCCESS; + }); + when(mockManipulations.triggerDescriptorUpdate(anyList())).thenReturn(ResponseTypes.Result.RESULT_FAIL); + final MdibEntity mockEntityB = mock(MdibEntity.class); + when(mockEntityB.getHandle()).thenReturn(parentDescriptorHandle); + when(mockEntityB.getChildren()).thenReturn(List.of(childDescriptorHandle)); + when(mockTestClient.getSdcRemoteDevice().getMdibAccess().findEntitiesByType(any())) + .thenReturn(List.of(mockEntityB)); + final MdibEntity mockEntityB2 = mock(MdibEntity.class); + when(mockTestClient.getSdcRemoteDevice().getMdibAccess().getEntity(any())) + .thenAnswer(args -> { + if (presenceMap.get((String) args.getArgument(0))) { + return Optional.of(mockEntityB2); + } else { + return Optional.empty(); + } + }); + + assertFalse( + ManipulationPreconditions.DescriptionModificationAllWithParentChildRelationshipPrecondition + .manipulation(injector)); + + final var insertCaptor = ArgumentCaptor.forClass(String.class); + final var removeCaptor = ArgumentCaptor.forClass(String.class); + final var handleCaptor = ArgumentCaptor.forClass(List.class); + verify(mockManipulations, times(1)).getRemovableDescriptorsOfClass(); + verify(mockManipulations, times(0)).insertDescriptor(insertCaptor.capture()); + verify(mockManipulations, times(0)).removeDescriptor(removeCaptor.capture()); + verify(mockManipulations, times(1)).triggerDescriptorUpdate(handleCaptor.capture()); + + assertEquals(2, handleCaptor.getAllValues().get(0).size()); + assertEquals(childDescriptorHandle, handleCaptor.getAllValues().get(0).get(0)); + assertEquals(parentDescriptorHandle, handleCaptor.getAllValues().get(0).get(1)); + } }